Skip to content

Commit d472942

Browse files
committed
Support for uploading templates for installing packs
1 parent e09659a commit d472942

File tree

6 files changed

+187
-13
lines changed

6 files changed

+187
-13
lines changed

app/Http/Controllers/Admin/PackController.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ public function listByService(Request $request, $id)
9797

9898
public function new(Request $request, $opt = null)
9999
{
100-
101100
return view('admin.services.packs.new', [
102101
'services' => $this->formatServices(),
103102
'packFor' => $opt,
@@ -106,7 +105,6 @@ public function new(Request $request, $opt = null)
106105

107106
public function create(Request $request)
108107
{
109-
// dd($request->all());
110108
try {
111109
$repo = new Pack;
112110
$id = $repo->create($request->except([
@@ -123,7 +121,6 @@ public function create(Request $request)
123121
Alert::danger('An error occured while attempting to add a new service pack.')->flash();
124122
}
125123
return redirect()->route('admin.services.packs.new', $request->input('option'))->withInput();
126-
127124
}
128125

129126
public function edit(Request $request, $id)
@@ -179,7 +176,7 @@ public function export(Request $request, $id, $files = false)
179176
if ((bool) $files) {
180177
$zip = new \ZipArchive;
181178
if (!$zip->open($filename, \ZipArchive::CREATE)) {
182-
exit("cannot open <$filename>\n");
179+
abort(503, 'Unable to open file for writing.');
183180
}
184181

185182
$files = Storage::files('packs/' . $pack->uuid);
@@ -200,4 +197,31 @@ public function export(Request $request, $id, $files = false)
200197
])->deleteFileAfterSend(true);
201198
}
202199
}
200+
201+
public function uploadForm(Request $request, $for = null) {
202+
return view('admin.services.packs.upload', [
203+
'services' => $this->formatServices(),
204+
'for' => $for
205+
]);
206+
}
207+
208+
public function postUpload(Request $request)
209+
{
210+
try {
211+
$repo = new Pack;
212+
$id = $repo->createWithTemplate($request->except([
213+
'_token'
214+
]));
215+
Alert::success('Successfully created new service!')->flash();
216+
return redirect()->route('admin.services.packs.edit', $id)->withInput();
217+
} catch (DisplayValidationException $ex) {
218+
return redirect()->back()->withErrors(json_decode($ex->getMessage()))->withInput();
219+
} catch (DisplayException $ex) {
220+
Alert::danger($ex->getMessage())->flash();
221+
} catch (\Exception $ex) {
222+
Log::error($ex);
223+
Alert::danger('An error occured while attempting to add a new service pack.')->flash();
224+
}
225+
return redirect()->back();
226+
}
203227
}

app/Http/Routes/AdminRoutes.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,13 @@ public function map(Router $router) {
446446
$router->post('/new', [
447447
'uses' => 'Admin\PackController@create'
448448
]);
449+
$router->get('/upload/{option?}', [
450+
'as' => 'admin.services.packs.uploadForm',
451+
'uses' => 'Admin\PackController@uploadForm'
452+
]);
453+
$router->post('/upload', [
454+
'uses' => 'Admin\PackController@postUpload'
455+
]);
449456
$router->get('/', [
450457
'as' => 'admin.services.packs',
451458
'uses' => 'Admin\PackController@listAll'

app/Repositories/ServiceRepository/Pack.php

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function create(array $data)
4646
$validator = Validator::make($data, [
4747
'name' => 'required|string',
4848
'version' => 'required|string',
49-
'description' => 'string',
49+
'description' => 'sometimes|nullable|string',
5050
'option' => 'required|exists:service_options,id',
5151
'selectable' => 'sometimes|boolean',
5252
'visible' => 'sometimes|boolean',
@@ -55,7 +55,7 @@ public function create(array $data)
5555
'build_cpu' => 'required|integer|min:0',
5656
'build_io' => 'required|integer|min:10|max:1000',
5757
'build_container' => 'required|string',
58-
'build_script' => 'sometimes|string'
58+
'build_script' => 'sometimes|nullable|string'
5959
]);
6060

6161
if ($validator->fails()) {
@@ -75,7 +75,8 @@ public function create(array $data)
7575
}
7676
}
7777

78-
DB::transaction(function () use ($data) {
78+
DB::beginTransaction();
79+
try {
7980
$uuid = new UuidService;
8081
$pack = Models\ServicePack::create([
8182
'option' => $data['option'],
@@ -93,13 +94,94 @@ public function create(array $data)
9394
'visible' => isset($data['visible'])
9495
]);
9596

96-
$filename = ($data['file_upload']->getMimeType() === 'application/zip') ? 'archive.zip' : 'archive.tar.gz';
97-
$data['file_upload']->storeAs('packs/' . $pack->uuid, $filename);
97+
Storage::makeDirectory('packs/' . $pack->uuid);
98+
if (isset($data['file_upload'])) {
99+
$filename = ($data['file_upload']->getMimeType() === 'application/zip') ? 'archive.zip' : 'archive.tar.gz';
100+
$data['file_upload']->storeAs('packs/' . $pack->uuid, $filename);
101+
}
102+
103+
DB::commit();
104+
} catch (\Exception $ex) {
105+
DB::rollBack();
106+
throw $ex;
107+
}
108+
109+
return $pack->id;
110+
}
111+
112+
public function createWithTemplate(array $data)
113+
{
114+
if (!isset($data['file_upload'])) {
115+
throw new DisplayException('No template file was found submitted with this request.');
116+
}
117+
118+
if (!$data['file_upload']->isValid()) {
119+
throw new DisplayException('The file provided does not appear to be valid.');
120+
}
121+
122+
if (!in_array($data['file_upload']->getMimeType(), [
123+
'application/zip',
124+
'text/plain',
125+
'application/json'
126+
])) {
127+
throw new DisplayException('The file provided (' . $data['file_upload']->getMimeType() . ') does not meet the required filetypes of application/zip or application/json.');
128+
}
129+
130+
if ($data['file_upload']->getMimeType() === 'application/zip') {
131+
$zip = new \ZipArchive;
132+
if (!$zip->open($data['file_upload']->path())) {
133+
throw new DisplayException('The uploaded archive was unable to be opened.');
134+
}
135+
136+
$isZip = $zip->locateName('archive.zip');
137+
$isTar = $zip->locateName('archive.tar.gz');
138+
139+
if ($zip->locateName('import.json') === false || ($isZip === false && $isTar === false)) {
140+
throw new DisplayException('This contents of the provided archive were in an invalid format.');
141+
}
142+
143+
$json = json_decode($zip->getFromName('import.json'));
144+
$id = $this->create([
145+
'name' => $json->name,
146+
'version' => $json->version,
147+
'description' => $json->description,
148+
'option' => $data['option'],
149+
'selectable' => $json->selectable,
150+
'visible' => $json->visible,
151+
'build_memory' => $json->build->memory,
152+
'build_swap' => $json->build->swap,
153+
'build_cpu' => $json->build->cpu,
154+
'build_io' => $json->build->io,
155+
'build_container' => $json->build->container,
156+
'build_script' => $json->build->script
157+
]);
98158

99-
$pack->save();
159+
$pack = Models\ServicePack::findOrFail($id);
160+
if (!$zip->extractTo(storage_path('app/packs/' . $pack->uuid), ($isZip === false) ? 'archive.tar.gz' : 'archive.zip')) {
161+
$pack->delete();
162+
throw new DisplayException('Unable to extract the archive file to the correct location.');
163+
}
100164

165+
$zip->close();
101166
return $pack->id;
102-
});
167+
} else {
168+
$json = json_decode(file_get_contents($data['file_upload']->path()));
169+
return $this->create([
170+
'name' => $json->name,
171+
'version' => $json->version,
172+
'description' => $json->description,
173+
'option' => $data['option'],
174+
'selectable' => $json->selectable,
175+
'visible' => $json->visible,
176+
'build_memory' => $json->build->memory,
177+
'build_swap' => $json->build->swap,
178+
'build_cpu' => $json->build->cpu,
179+
'build_io' => $json->build->io,
180+
'build_container' => $json->build->container,
181+
'build_script' => $json->build->script
182+
]);
183+
}
184+
103185
}
104186

105187
public function update($id, array $data)

resources/views/admin/services/packs/byoption.blade.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
<a href="{{ route('admin.services.packs.new', $option->id) }}">
5959
<button class="pull-right btn btn-xxs btn-primary"><i class="fa fa-plus"></i></button>
6060
</a>
61-
<a href="{{ route('admin.services.packs.new', $option->id) }}">
61+
<a href="#upload" id="toggleUpload">
6262
<button class="pull-right btn btn-xxs btn-default" style="margin-right:5px;"><i class="fa fa-upload"></i> Install from Template</button>
6363
</a>
6464
</td>
@@ -69,6 +69,22 @@
6969
<script>
7070
$(document).ready(function () {
7171
$('#sidebar_links').find("a[href='/admin/services/packs']").addClass('active');
72+
$('#toggleUpload').on('click', function (event) {
73+
event.preventDefault();
74+
var element = $(this);
75+
element.find('button').addClass('disabled');
76+
$.ajax({
77+
method: 'GET',
78+
url: '{{ route('admin.services.packs.uploadForm', $option->id) }}'
79+
}).fail(function (jqXhr) {
80+
console.error(jqXhr);
81+
alert('There was an error trying to create the upload form.');
82+
}).success(function (data) {
83+
$(data).modal();
84+
}).always(function () {
85+
element.find('button').removeClass('disabled');
86+
});
87+
});
7288
});
7389
</script>
7490
@endsection

resources/views/admin/services/packs/new.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@
152152
<label class="control-label">Package Archive:</label>
153153
<input name="file_upload" type="file" accept=".zip,.tar.gz, application/zip, application/gzip" />
154154
<p class="text-muted"><small>This package file must either be a <code>.zip</code> or <code>.tar.gz</code> archive of files to use for either building or running this pack.<br /><br />If your file is larger than <code>20MB</code> we recommend uploading it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file.
155-
This is currently configured with the following limits: <code>upload_max_filesize={{ ini_get('upload_max_filesize') }}</code> and <code>post_max_size={{ ini_get('post_max_size') }}</code>. If your file is larger than either of those values this request will fail.</small></p>
155+
This server is currently configured with the following limits: <code>upload_max_filesize={{ ini_get('upload_max_filesize') }}</code> and <code>post_max_size={{ ini_get('post_max_size') }}</code>. If your file is larger than either of those values this request will fail.</small></p>
156156
</div>
157157
</div>
158158
</div>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<div class="modal fade" tabindex="-1" role="dialog">
2+
<div class="modal-dialog" role="document">
3+
<div class="modal-content">
4+
<form action="{{ route('admin.services.packs.uploadForm') }}" method="POST" enctype="multipart/form-data">
5+
<div class="modal-header">
6+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
7+
<h4 class="modal-title">Install Pack from Template</h4>
8+
</div>
9+
<div class="modal-body">
10+
<div class="well" style="margin-bottom:0">
11+
<div class="row">
12+
<div class="col-md-12">
13+
<label class="control-label">Associated Service Option:</label>
14+
<select name="option" class="form-control">
15+
@foreach($services as $service => $options)
16+
<option disabled>{{ $service }}</option>
17+
@foreach($options as $option)
18+
<option value="{{ $option['id'] }}" @if((int) $for === (int) $option['id'])selected="selected"@endif>&nbsp;&nbsp; -- {{ $option['name'] }}</option>
19+
@endforeach
20+
@endforeach
21+
</select>
22+
</div>
23+
</div>
24+
<div class="row" style="margin-top:15px;">
25+
<div class="col-md-12">
26+
<div class="row">
27+
<div class="form-group col-md-12">
28+
<label class="control-label">Package Archive:</label>
29+
<input name="file_upload" type="file" accept=".zip,.json, application/json, application/zip" />
30+
<p class="text-muted"><small>This file should be either the <code>.json</code> template file, or a <code>.zip</code> pack archive containing <code>archive.(zip|tar.gz)</code> and <code>import.json</code> within.<br /><br />This server is currently configured with the following limits: <code>upload_max_filesize={{ ini_get('upload_max_filesize') }}</code> and <code>post_max_size={{ ini_get('post_max_size') }}</code>. If your file is larger than either of those values this request will fail.</small></p>
31+
</div>
32+
</div>
33+
</div>
34+
</div>
35+
</div>
36+
</div>
37+
<div class="modal-footer">
38+
{!! csrf_field() !!}
39+
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">Cancel</button>
40+
<input type="submit" class="btn btn-primary btn-sm" value="Install" />
41+
</div>
42+
</form>
43+
</div>
44+
</div>
45+
</div>

0 commit comments

Comments
 (0)