Skip to content

Commit 19c4fec

Browse files
committed
Issues-104:Using ClientFileNames
1 parent 9187eb2 commit 19c4fec

File tree

2 files changed

+263
-1
lines changed

2 files changed

+263
-1
lines changed

vanilla/applications/dashboard/controllers/api/MediaApiController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ private function doUpload(UploadedFile $upload, $type) {
116116

117117
$ext = pathinfo(strtolower($upload->getClientFilename()), PATHINFO_EXTENSION);
118118
$destination = $this->generateUploadPath($ext, true);
119-
$uploadResult = $this->saveUpload($upload, $destination);
119+
$uploadResult = $this->saveUpload($upload, $destination, '%s', false , [ 'ClientFileName' => $upload->getClientFilename()]);
120120
$media['Path'] = $uploadResult['SaveName'];
121121

122122
$id = $this->mediaModel->save($media);
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
<?php
2+
/**
3+
* @author Todd Burry <todd@vanillaforums.com>
4+
* @copyright 2009-2019 Vanilla Forums Inc.
5+
* @license GPL-2.0-only
6+
*/
7+
8+
namespace Vanilla\Web;
9+
10+
use Garden\EventManager;
11+
use Garden\Schema\Schema;
12+
use Garden\Schema\Validation;
13+
use Garden\Schema\ValidationException;
14+
use Garden\Web\Exception\HttpException;
15+
use Gdn_Locale as LocaleInterface;
16+
use Gdn_Session as SessionInterface;
17+
use Gdn_Upload as Upload;
18+
use Vanilla\Exception\PermissionException;
19+
use Vanilla\InjectableInterface;
20+
use Vanilla\UploadedFile;
21+
use Vanilla\Utility\ModelUtils;
22+
23+
/**
24+
* The controller base class.
25+
*/
26+
abstract class Controller implements InjectableInterface {
27+
/**
28+
* @var SessionInterface
29+
*/
30+
private $session;
31+
32+
/**
33+
* @var EventManager
34+
*/
35+
private $eventManager;
36+
37+
/**
38+
* @var LocaleInterface;
39+
*/
40+
private $locale;
41+
42+
/** @var Upload */
43+
private $upload;
44+
45+
/**
46+
* Set the base dependencies of the controller.
47+
*
48+
* This method allows subclasses to declare their dependencies in their constructor without worrying about these
49+
* dependencies.
50+
*
51+
* @param SessionInterface|null $session The session of the current user.
52+
* @param EventManager|null $eventManager The event manager dependency.
53+
* @param LocaleInterface|null $local The current locale for translations.
54+
* @param Upload $upload File upload handler.
55+
*/
56+
public function setDependencies(
57+
SessionInterface $session = null,
58+
EventManager $eventManager = null,
59+
LocaleInterface $local = null,
60+
Upload $upload
61+
) {
62+
$this->session = $session;
63+
$this->eventManager = $eventManager;
64+
$this->locale = $local;
65+
$this->upload = $upload;
66+
}
67+
68+
/**
69+
* Enforce the following permission(s) or throw an exception that the dispatcher can handle.
70+
*
71+
* When passing several permissions to check the user can have any of the permissions. If you want to force several
72+
* permissions then make several calls to this method.
73+
*
74+
* @throws \Exception if no session is available.
75+
* @throws HttpException if a ban has been applied on the permission(s) for this session.
76+
* @throws PermissionException if the user does not have the specified permission(s).
77+
*
78+
* @param string|array $permission The permissions you are requiring.
79+
* @param int|null $id The ID of the record we are checking the permission of.
80+
*/
81+
public function permission($permission = null, $id = null) {
82+
if (!$this->session instanceof SessionInterface) {
83+
throw new \Exception("Session not available.", 500);
84+
}
85+
$permissions = (array)$permission;
86+
87+
/**
88+
* First check to see if the user is banned.
89+
*/
90+
if ($ban = $this->session->getPermissions()->getBan($permissions)) {
91+
$ban += ['code' => 401, 'msg' => 'Access denied.'];
92+
93+
throw HttpException::createFromStatus($ban['code'], $ban['msg'], $ban);
94+
}
95+
96+
if (!$this->session->getPermissions()->hasAny($permissions, $id)) {
97+
throw new PermissionException($permissions);
98+
}
99+
}
100+
101+
/**
102+
* Create a schema attached to an endpoint.
103+
*
104+
* @param array|Schema $schema The schema definition. This can be either an array or an actual schema object.
105+
* @param string|array $type The type of schema. This can be one of the following:
106+
*
107+
* - **"in" or "out"**. Says this is an input or output schema.
108+
* - **"TypeID"**. Says this the name of the schema being defined, but not used in an endpoint. You specify a type
109+
* ID so the schema is pluggable. You name a type like you name a class.
110+
* - **["TypeID", "in" or "out"]**. When you need to define both a type ID and input or output.
111+
* @return Schema Returns a schema object.
112+
*/
113+
public function schema($schema, $type = 'in') {
114+
$id = '';
115+
if (is_array($type)) {
116+
$origType = $type;
117+
list($id, $type) = $origType;
118+
} elseif (!in_array($type, ['in', 'out'], true)) {
119+
$id = $type;
120+
$type = '';
121+
}
122+
123+
// Figure out the name.
124+
if (is_array($schema)) {
125+
$schema = Schema::parse($schema);
126+
} elseif ($schema instanceof Schema) {
127+
$schema = clone $schema;
128+
}
129+
130+
// Fire an event for schema modification.
131+
if (!empty($id)) {
132+
// The type is a specific type of schema.
133+
$schema->setID($id);
134+
135+
$this->eventManager->fire("{$id}Schema_init", $schema);
136+
}
137+
138+
// Fire a generic schema event for documentation.
139+
if (!empty($type)) {
140+
$this->eventManager->fire("controller_schema", $this, $schema, $type);
141+
}
142+
143+
return $schema;
144+
}
145+
146+
/**
147+
* Get the session.
148+
*
149+
* @return SessionInterface Returns the session.
150+
*/
151+
public function getSession() {
152+
return $this->session;
153+
}
154+
155+
/**
156+
* Set the session.
157+
*
158+
* @param SessionInterface $session The new session.
159+
* @return $this
160+
*/
161+
public function setSession($session) {
162+
$this->session = $session;
163+
return $this;
164+
}
165+
166+
/**
167+
* Get the event manager.
168+
*
169+
* @return EventManager Returns the event manager.
170+
*/
171+
public function getEventManager() {
172+
return $this->eventManager;
173+
}
174+
175+
/**
176+
* Set the event manager.
177+
*
178+
* @param EventManager $eventManager The new event manager.
179+
* @return $this
180+
*/
181+
public function setEventManager($eventManager) {
182+
$this->eventManager = $eventManager;
183+
return $this;
184+
}
185+
186+
/**
187+
* Get the locale.
188+
*
189+
* @return LocaleInterface Returns the locale.
190+
*/
191+
public function getLocale() {
192+
return $this->locale;
193+
}
194+
195+
/**
196+
* Set the locale.
197+
*
198+
* @param LocaleInterface $locale The locale of the current user.
199+
* @return $this
200+
*/
201+
public function setLocale($locale) {
202+
$this->locale = $locale;
203+
return $this;
204+
}
205+
206+
/**
207+
* Generate a valid upload path, relative to the uploads directory.
208+
*
209+
* @param string $ext The file's extension.
210+
* @param bool $chunk Include an additional random subdirectory?
211+
* @return string
212+
*/
213+
public function generateUploadPath($ext, $chunk = false) {
214+
$path = $this->upload->generateTargetName(PATH_UPLOADS, $ext, $chunk);
215+
$result = stringBeginsWith($path, PATH_UPLOADS.'/', false, true);
216+
return $result;
217+
}
218+
219+
/**
220+
* @param UploadedFile $upload
221+
* @param string $destination
222+
* @param string $nameFormat
223+
* @param bool $copy
224+
* @throws \Exception if failed to save the upload.
225+
* @returns array|bool
226+
*/
227+
public function saveUpload(UploadedFile $upload, $destination, $nameFormat = '%s', $copy = false, $options = []) {
228+
$destination = $result = stringBeginsWith($destination, PATH_UPLOADS.'/', false, true);
229+
$ext = pathinfo($destination, PATHINFO_EXTENSION);
230+
$baseName = basename($destination, ".{$ext}");
231+
$dirName = dirname($destination);
232+
233+
$target = sprintf($nameFormat, $baseName);
234+
if (!empty($ext)) {
235+
$target .= ".{$ext}";
236+
}
237+
if (!empty($dirName)) {
238+
$target = "{$dirName}/{$target}";
239+
}
240+
$target = PATH_UPLOADS."/{$target}";
241+
242+
$result = $this->upload->saveAs(
243+
$upload->getFile(),
244+
$target,
245+
$options,
246+
$copy
247+
);
248+
return $result;
249+
}
250+
251+
/**
252+
* Given a model, analyze its validation property and return failures.
253+
*
254+
* @param object $model The model to analyze the Validation property of.
255+
* @param bool $throw If errors are found, should an exception be thrown?
256+
* @throws ValidationException if errors are detected and $throw is true.
257+
* @return Validation
258+
*/
259+
public function validateModel($model, $throw = true) {
260+
return ModelUtils::validationResultToValidationException($model, $this->locale, $throw);
261+
}
262+
}

0 commit comments

Comments
 (0)