diff --git a/src/IDF/Form/WikiResourceCreate.php b/src/IDF/Form/WikiResourceCreate.php index a1edfa1..8ef1e83 100644 --- a/src/IDF/Form/WikiResourceCreate.php +++ b/src/IDF/Form/WikiResourceCreate.php @@ -133,7 +133,6 @@ class IDF_Form_WikiResourceCreate extends Pluf_Form $resource->summary = trim($this->cleaned_data['summary']); $resource->title = trim($this->cleaned_data['title']); $resource->mime_type = $mimeType; - $resource->orig_file_ext = $extension; $resource->create(); // add the first revision @@ -142,6 +141,7 @@ class IDF_Form_WikiResourceCreate extends Pluf_Form $rev->submitter = $this->user; $rev->summary = __('Initial resource creation'); $rev->filesize = filesize($tempFile); + $rev->fileext = $extension; $rev->create(); $finalFile = $rev->getFilePath(); diff --git a/src/IDF/Form/WikiResourceUpdate.php b/src/IDF/Form/WikiResourceUpdate.php new file mode 100644 index 0000000..982280e --- /dev/null +++ b/src/IDF/Form/WikiResourceUpdate.php @@ -0,0 +1,161 @@ +resource = $extra['resource']; + $this->user = $extra['user']; + $this->project = $extra['project']; + + $this->fields['summary'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Description'), + 'help_text' => __('This one line description is displayed in the list of resources.'), + 'initial' => $this->resource->summary, + 'widget_attrs' => array( + 'maxlength' => 200, + 'size' => 67, + ), + )); + $this->fields['file'] = new Pluf_Form_Field_File( + array('required' => true, + 'label' => __('File'), + 'initial' => '', + 'max_size' => Pluf::f('max_upload_size', 2097152), + 'move_function_params' => array('upload_path' => $this->getTempUploadPath(), + 'upload_path_create' => true, + 'upload_overwrite' => true), + )); + + $this->fields['comment'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Comment'), + 'help_text' => __('One line to describe the changes you made.'), + 'initial' => '', + 'widget_attrs' => array( + 'maxlength' => 200, + 'size' => 67, + ), + )); + } + + public function clean_file() + { + // FIXME: we do the same in IDF_Form_Upload and a couple of other places as well + $extra = strtolower(implode('|', explode(' ', Pluf::f('idf_extra_upload_ext')))); + if (strlen($extra)) $extra .= '|'; + if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $this->cleaned_data['file'])) { + @unlink($this->getTempUploadPath().$this->cleaned_data['file']); + throw new Pluf_Form_Invalid(__('For security reasons, you cannot upload a file with this extension.')); + } + + list($mimeType, , $extension) = IDF_FileUtil::getMimeType($this->getTempUploadPath().$this->cleaned_data['file']); + if ($this->resource->mime_type != $mimeType) { + throw new Pluf_Form_Invalid(sprintf( + __('The mime type of the uploaded file "%s" does not match the mime type of this resource "%s"'), + $mimeType, $this->resource->mime_type + )); + } + $this->cleaned_data['fileext'] = $extension; + + if (md5_file($this->getTempUploadPath().$this->cleaned_data['file']) === + md5_file($this->resource->get_current_revision()->getFilePath())) { + throw new Pluf_Form_Invalid(__('The current version of the resource and the uploaded file are equal.')); + } + return $this->cleaned_data['file']; + } + + /** + * If we have uploaded a file, but the form failed remove it. + * + */ + function failed() + { + if (!empty($this->cleaned_data['file']) + and file_exists($this->getTempUploadPath().$this->cleaned_data['file'])) { + @unlink($this->getTempUploadPath().$this->cleaned_data['file']); + } + } + + /** + * Save the model in the database. + * + * @param bool Commit in the database or not. If not, the object + * is returned but not saved in the database. + * @return Object Model with data set from the form. + */ + function save($commit=true) + { + if (!$this->isValid()) { + throw new Exception(__('Cannot save the model from an invalid form.')); + } + + $tempFile = $this->getTempUploadPath().$this->cleaned_data['file']; + + $this->resource->summary = trim($this->cleaned_data['summary']); + $this->resource->update(); + + // add the new revision + $rev = new IDF_Wiki_ResourceRevision(); + $rev->wikiresource = $this->resource; + $rev->submitter = $this->user; + $rev->summary = $this->cleaned_data['comment']; + $rev->filesize = filesize($tempFile); + $rev->fileext = $this->cleaned_data['fileext']; + $rev->create(); + + $finalFile = $rev->getFilePath(); + if (!is_dir(dirname($finalFile))) { + @unlink($tempFile); + $rev->delete(); + throw new Exception('resource path does not exist'); + } + + if (!@rename($tempFile, $finalFile)) { + @unlink($tempFile); + $rev->delete(); + throw new Exception('could not move resource to final location'); + } + + return $this->resource; + } + + private function getTempUploadPath() + { + return Pluf::f('upload_path').'/'.$this->project->shortname.'/wiki/temp/'; + } +} diff --git a/src/IDF/Views/Wiki.php b/src/IDF/Views/Wiki.php index f157062..4d1ee5e 100644 --- a/src/IDF/Views/Wiki.php +++ b/src/IDF/Views/Wiki.php @@ -95,7 +95,7 @@ class IDF_Views_Wiki $pag->action = array('IDF_Views_Wiki::listResources', array($prj->shortname)); $pag->edit_action = array('IDF_Views_Wiki::viewResource', 'shortname', 'title'); $pag->forced_where = new Pluf_SQL('project=%s', array($prj->id)); - $pag->extra_classes = array('right', 'a-c', 'a-c', 'a-c'); + $pag->extra_classes = array('right', 'a-c', 'left', 'a-c'); $list_display = array( 'title' => __('Resource Title'), 'mime_type' => __('MIME type'), @@ -347,7 +347,7 @@ class IDF_Views_Wiki if (isset($request->GET['rev']) and preg_match('/^[0-9]+$/', $request->GET['rev'])) { $revision = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_ResourceRevision', $request->GET['rev']); - if ($oldrev->wikiresource != $resource->id or $oldrev->is_head == true) { + if ($revision->wikiresource != $resource->id or $revision->is_head == true) { return new Pluf_HTTP_Response_NotFound($request); } } @@ -382,7 +382,12 @@ class IDF_Views_Wiki return new Pluf_HTTP_Response_NotFound($request); } - return new Pluf_HTTP_Response_File($rev->getFilePath(), $res->mime_type); + $response = new Pluf_HTTP_Response_File($rev->getFilePath(), $res->mime_type); + if (isset($request->GET['attachment']) && $request->GET['attachment']) { + $response->headers['Content-Disposition'] = + 'attachment; filename="'.$res->title.'.'.$rev->fileext.'"'; + } + return $response; } /** @@ -425,7 +430,7 @@ class IDF_Views_Wiki } /** - * View a documentation page. + * Update a documentation page. */ public $updatePage_precond = array('IDF_Precondition::accessWiki', 'Pluf_Precondition::loginRequired'); @@ -475,6 +480,54 @@ class IDF_Views_Wiki $request); } + /** + * Update a documentation resource. + */ + public $updateResource_precond = array('IDF_Precondition::accessWiki', + 'Pluf_Precondition::loginRequired'); + public function updateResource($request, $match) + { + $prj = $request->project; + // Find the page + $sql = new Pluf_SQL('project=%s AND title=%s', + array($prj->id, $match[2])); + $resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen())); + if ($resources->count() != 1) { + return new Pluf_HTTP_Response_NotFound($request); + } + $resource = $resources[0]; + $title = sprintf(__('Update %s'), $resource->title); + $revision = $resource->get_current_revision(); + $params = array('project' => $prj, + 'user' => $request->user, + 'resource' => $resource); + if ($request->method == 'POST') { + $form = new IDF_Form_WikiResourceUpdate(array_merge($request->POST, $request->FILES), + $params); + if ($form->isValid()) { + $page = $form->save(); + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource', + array($prj->shortname, $resource->title)); + $request->user->setMessage(sprintf(__('The resource %s has been updated.'), + $url, Pluf_esc($resource->title))); + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::listResources', + array($prj->shortname)); + return new Pluf_HTTP_Response_Redirect($url); + } + } else { + $form = new IDF_Form_WikiResourceUpdate(null, $params); + } + + return Pluf_Shortcuts_RenderToResponse('idf/wiki/updateResource.html', + array( + 'page_title' => $title, + 'resource' => $resource, + 'rev' => $revision, + 'form' => $form, + ), + $request); + } + /** * Delete a Wiki page. */ diff --git a/src/IDF/Wiki/Resource.php b/src/IDF/Wiki/Resource.php index cc4c318..1504682 100644 --- a/src/IDF/Wiki/Resource.php +++ b/src/IDF/Wiki/Resource.php @@ -72,14 +72,6 @@ class IDF_Wiki_Resource extends Pluf_Model 'verbose' => __('MIME media type'), 'help_text' => __('The MIME media type of the resource.'), ), - 'orig_file_ext' => - array( - 'type' => 'Pluf_DB_Field_Varchar', - 'blank' => false, - 'size' => 10, - 'verbose' => __('Original file extension'), - 'help_text' => __('The original file extension of the uploaded resource.'), - ), 'summary' => array( 'type' => 'Pluf_DB_Field_Varchar', diff --git a/src/IDF/Wiki/ResourceRevision.php b/src/IDF/Wiki/ResourceRevision.php index 59e319f..4a0a3b7 100644 --- a/src/IDF/Wiki/ResourceRevision.php +++ b/src/IDF/Wiki/ResourceRevision.php @@ -70,6 +70,14 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model 'default' => 0, 'verbose' => __('file size in bytes'), ), + 'fileext' => + array( + 'type' => 'Pluf_DB_Field_Varchar', + 'blank' => false, + 'size' => 10, + 'verbose' => __('File extension'), + 'help_text' => __('The file extension of the uploaded resource.'), + ), 'submitter' => array( 'type' => 'Pluf_DB_Field_Foreignkey', @@ -105,6 +113,25 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model return ''; } + function preDelete() + { + // if we kill off a head revision, ensure that we either mark a previous + // revision as head or kill off the resource record as well + if ($this->is_head) { + $sql = new Pluf_SQL('wikiresource=%s and id!=%s', array($this->wikiresource, $this->id)); + $revs = Pluf::factory('IDF_Wiki_ResourceRevision')->getList(array('filter'=>$sql->gen(), 'order'=>'id DESC')); + if ($revs->count() > 0) { + $previous = $revs[0]; + $previous->is_head = true; + $previous->update(); + } else { + $this->get_wikiresource()->delete(); + } + } + + @unlink($this->getFilePath()); + } + function preSave($create=false) { if ($this->id == '') { @@ -135,7 +162,7 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model function getFilePath() { return sprintf(Pluf::f('upload_path').'/'.$this->get_wikiresource()->get_project()->shortname.'/wiki/res/%d/%d.%s', - $this->get_wikiresource()->id, $this->id, $this->get_wikiresource()->orig_file_ext); + $this->get_wikiresource()->id, $this->id, $this->fileext); } function getFileURL() @@ -145,11 +172,6 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model array($prj->shortname, $this->id)); } - function preDelete() - { - @unlink($this->getFilePath()); - } - /** * Returns the page revisions which contain references to this resource revision */ diff --git a/src/IDF/templates/idf/wiki/updateResource.html b/src/IDF/templates/idf/wiki/updateResource.html new file mode 100644 index 0000000..d93fe39 --- /dev/null +++ b/src/IDF/templates/idf/wiki/updateResource.html @@ -0,0 +1,46 @@ +{extends "idf/wiki/base.html"} +{block docclass}yui-t2{/block} +{block body} + +{if $form.errors} +
+

{trans 'The form contains some errors. Please correct them to update the page.'}

+{if $form.get_top_errors} +{$form.render_top_errors|unsafe} +{/if} +
+{/if} + +
+ + + + + + + + + + + + + + + + + +
{$form.f.summary.labelTag}:{if $form.f.summary.errors}{$form.f.summary.fieldErrors}{/if} +{$form.f.summary|unsafe}
+{$form.f.summary.help_text} +
{$form.f.file.labelTag}:{if $form.f.file.errors}{$form.f.file.fieldErrors}{/if} +{$form.f.file|unsafe} +
{$form.f.comment.labelTag}:{if $form.f.comment.errors}{$form.f.comment.fieldErrors}{/if} +{$form.f.comment|unsafe}
+{$form.f.comment.help_text} +
 {* float left is a fix for Firefox < 3.5 *} + | {trans 'Cancel'}{if $isOwner or $isAdmin or $isMember} +{aurl 'url', 'IDF_Views_Wiki::deleteResource', array($project.shortname, $resource.id)} +{trans 'Trash'} {trans 'Delete this resource'}{/if} +
+
+{/block} diff --git a/src/IDF/templates/idf/wiki/viewResource.html b/src/IDF/templates/idf/wiki/viewResource.html index 3cd4e8d..149159d 100644 --- a/src/IDF/templates/idf/wiki/viewResource.html +++ b/src/IDF/templates/idf/wiki/viewResource.html @@ -8,7 +8,7 @@ {block body} {if !$rev.is_head} -{ashowuser 'submitter', $oldrev.get_submitter(), $request}{aurl 'url', 'IDF_Views_Wiki::viewResource', array($project.shortname, $resource.title)} +{ashowuser 'submitter', $rev.get_submitter(), $request}{aurl 'url', 'IDF_Views_Wiki::viewResource', array($project.shortname, $resource.title)}

{blocktrans}You are looking at an old revision of the resource {$resource.title}. This revision was created @@ -21,9 +21,11 @@ by {$submitter}.{/blocktrans}

{$rev.render()|unsafe}

+{aurl 'url', 'IDF_Views_Wiki::rawResource', array($project.shortname, $rev.id), array('attachment' => 1)} {if ($isOwner or $isAdmin) and !$rev.is_head}{aurl 'url', 'IDF_Views_Wiki::deleteResourceRev', array($project.shortname, $rev.id)}

{trans 'Trash'} {trans 'Delete this revision'}