Index: image.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/image/image.module,v
retrieving revision 1.301
diff -u -p -r1.301 image.module
--- image.module 8 Mar 2009 21:40:38 -0000 1.301
+++ image.module 9 Mar 2009 02:11:03 -0000
@@ -172,66 +172,6 @@ function image_operations_rebuild($nids)
}
/**
- * TODO: document me...
- */
-function image_node_form_submit($form, &$form_state) {
- // We need to be aware that a user may try to edit multiple image nodes at
- // once. By using the $nid variable each node's files can be stored separately
- // in the session.
- $nid = $form_state['values']['nid'] ? $form_state['values']['nid'] : 'new_node';
- // When you enter the edit view the first time we need to clear our files in
- // session for this node. This is so if you upload a file, then decide you
- // don't want it and reload the form (without posting), the files will be
- // discarded.
- if (count($_POST) == 0) {
- unset($_SESSION['image_new_files'][$nid]);
- }
-
- // Validators for file_save_upload().
- $validators = array(
- 'file_validate_is_image' => array(),
- );
-
- if ($file = file_save_upload('image', $validators)) {
- // Resize the original.
- $image_info = image_get_info($file->filepath);
- $aspect_ratio = $image_info['height'] / $image_info['width'];
- $original_size = image_get_sizes(IMAGE_ORIGINAL, $aspect_ratio);
- if (!empty($original_size['width']) && !empty($original_size['height'])) {
- $result = image_scale($file->filepath, $file->filepath, $original_size['width'], $original_size['height']);
- if ($result) {
- clearstatcache();
- $file->filesize = filesize($file->filepath);
- drupal_set_message(t('The original image was resized to fit within the maximum allowed resolution of %width x %height pixels.', array('%width' => $original_size['width'], '%height' => $original_size['height'])));
- }
- }
-
- // Check the file size limit.
- if ($file->filesize > variable_get('image_max_upload_size', 800) * 1024) {
- form_set_error('image', t('The image you uploaded was too big. You are only allowed upload files less than %max_size but your file was %file_size.', array('%max_size' => format_size(variable_get('image_max_upload_size', 800) * 1024), '%file_size' => format_size($file->filesize))));
- file_delete($file->filepath);
- return;
- }
-
- // We're good to go.
- $form_state['values']['images'][IMAGE_ORIGINAL] = $file->filepath;
- $form_state['values']['rebuild_images'] = FALSE;
- $form_state['values']['new_file'] = TRUE;
-
- // Call hook to allow other modules to modify the original image.
- module_invoke_all('image_alter', $form_state['values'], $file->filepath, IMAGE_ORIGINAL);
- $form_state['values']['images'] = _image_build_derivatives((object) $form_state['values'], TRUE);
-
- // Store the new file into the session.
- $_SESSION['image_new_files'][$nid] = $form_state['values']['images'];
- }
- // Reload new files uploaded in a previous preview.
- else if (isset($_SESSION['image_new_files'][$nid])) {
- $form_state['values']['images'] = $_SESSION['image_new_files'][$nid];
- }
-}
-
-/**
* Implementation of hook_file_download().
*
* Note that in Drupal 5, the upload.module's hook_file_download() checks its
@@ -357,14 +297,19 @@ function image_form_add_thumbnail($form,
}
/**
- * Implementation of hook_form
+ * Implementation of hook_form().
*/
-function image_form(&$node, &$param) {
+function image_form(&$node, $form_state) {
_image_check_settings();
+ if (!$_POST && !empty($_SESSION['image_upload'])) {
+ unset($_SESSION['image_upload']);
+ }
+
$type = node_get_types('type', $node);
- $form['#submit'][] = 'image_node_form_submit';
+ $form['#validate'][] = 'image_form_validate';
+ $form['#submit'][] = 'image_form_submit';
$form['title'] = array(
'#type' => 'textfield',
@@ -401,7 +346,7 @@ function image_form(&$node, &$param) {
'#access' => (!isset($node->nid) ? FALSE : TRUE),
);
- $form['#attributes'] = array("enctype" => "multipart/form-data");
+ $form['#attributes'] = array('enctype' => 'multipart/form-data');
$form['image'] = array(
'#type' => 'file',
'#title' => t('Image'),
@@ -416,10 +361,66 @@ function image_form(&$node, &$param) {
return $form;
}
-function image_validate($node) {
- $nid = ($node->nid) ? $node->nid : 'new_node';
- if (!isset($node->images[IMAGE_ORIGINAL]) && !isset($_SESSION['image_new_files'][$nid])) {
- form_set_error('image', t('You must upload an image.'));
+function image_form_validate($form, &$form_state) {
+ // Avoid blocking node deletion with missing image.
+ if ($form_state['values']['op'] == t('Delete')) {
+ return;
+ }
+
+ // Validators for file_save_upload().
+ $validators = array(
+ 'file_validate_is_image' => array(),
+ );
+
+ // New image uploads need to be saved in images/temp in order to be viewable
+ // during node preview.
+ $temporary_file_path = file_create_path(file_directory_path() . '/' . variable_get('image_default_path', 'images') .'/temp');
+
+ if ($file = file_save_upload('image', $validators, $temporary_file_path)) {
+ // Resize the original.
+ $image_info = image_get_info($file->filepath);
+ $aspect_ratio = $image_info['height'] / $image_info['width'];
+ $original_size = image_get_sizes(IMAGE_ORIGINAL, $aspect_ratio);
+ if (!empty($original_size['width']) && !empty($original_size['height'])) {
+ $result = image_scale($file->filepath, $file->filepath, $original_size['width'], $original_size['height']);
+ if ($result) {
+ clearstatcache();
+ $file->filesize = filesize($file->filepath);
+ drupal_set_message(t('The original image was resized to fit within the maximum allowed resolution of %width x %height pixels.', array('%width' => $original_size['width'], '%height' => $original_size['height'])));
+ }
+ }
+
+ // Check the file size limit.
+ if ($file->filesize > variable_get('image_max_upload_size', 800) * 1024) {
+ form_set_error('image', t('The image you uploaded was too big. You are only allowed upload files less than %max_size but your file was %file_size.', array('%max_size' => format_size(variable_get('image_max_upload_size', 800) * 1024), '%file_size' => format_size($file->filesize))));
+ file_delete($file->filepath);
+ return;
+ }
+
+ // We're good to go.
+ $form_state['values']['images'][IMAGE_ORIGINAL] = $file->filepath;
+ $form_state['values']['rebuild_images'] = FALSE;
+ $form_state['values']['new_file'] = TRUE;
+
+ // Call hook to allow other modules to modify the original image.
+ module_invoke_all('image_alter', $form_state['values'], $form_state['values']['images'][IMAGE_ORIGINAL], IMAGE_ORIGINAL);
+ $form_state['values']['images'] = _image_build_derivatives((object) $form_state['values'], TRUE);
+
+ // Store the new file into the session.
+ $_SESSION['image_upload'] = $form_state['values']['images'];
+ }
+ elseif (empty($form_state['values']['images'][IMAGE_ORIGINAL])) {
+ if (empty($_SESSION['image_upload'])) {
+ form_set_error('image', t('You must upload an image.'));
+ }
+ }
+}
+
+function image_form_submit($form, &$form_state) {
+ if (!empty($_SESSION['image_upload'])) {
+ $form_state['values']['images'] = $_SESSION['image_upload'];
+ $form_state['values']['new_file'] = TRUE;
+ unset($_SESSION['image_upload']);
}
}
Index: tests/image.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/image/tests/image.test,v
retrieving revision 1.3
diff -u -p -r1.3 image.test
--- tests/image.test 1 Feb 2009 03:10:34 -0000 1.3
+++ tests/image.test 9 Mar 2009 02:21:46 -0000
@@ -8,7 +8,7 @@ class ImageTestCase extends DrupalWebTes
protected $web_user;
protected $image;
protected $another_image;
-
+
function getInfo() {
return array(
'name' => t('Image functionality'),
@@ -19,14 +19,14 @@ class ImageTestCase extends DrupalWebTes
function setUp() {
parent::setUp('image');
-
+
// User to create images.
$this->web_user = $this->drupalCreateUser(array('create images', 'view original images', 'edit own images', 'edit images'));
$this->drupalLogin($this->web_user);
-
+
// Uploadable image.
- $this->image = 'misc' . DIRECTORY_SEPARATOR . 'druplicon.png';
- $this->another_image = 'misc' . DIRECTORY_SEPARATOR . 'throbber.gif';
+ $this->image = 'misc/druplicon.png';
+ $this->another_image = 'misc/throbber.gif';
// Set small dimensions for testing scale so $this->image is small enough.
$image_sizes = image_get_sizes();
@@ -39,11 +39,33 @@ class ImageTestCase extends DrupalWebTes
$image_sizes['preview']['height'] = 10;
variable_set('image_sizes', $image_sizes);
}
-
+
+ /**
+ * Clean-up temporary files.
+ *
+ * @see system_cron()
+ *
+ * @todo This lets SimpleTest die for any reason.
+ */
+ function __tearDown() {
+ $result = db_query('SELECT * FROM {files} WHERE status = %d', FILE_STATUS_TEMPORARY);
+ while ($file = db_fetch_object($result)) {
+ if (file_exists($file->filepath)) {
+ // If files that exist cannot be deleted, continue so the database remains
+ // consistent.
+ if (!file_delete($file->filepath)) {
+ $this->error(t('Could not delete temporary file "%path" during garbage collection', array('%path' => $file->filepath)));
+ continue;
+ }
+ }
+ db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+ }
+ }
+
/**
* Verify creating/displaying/editing/deleting image nodes.
*/
- function testNode() {
+ function testImageNode() {
// Create an image.
$edit = array(
'title' => $this->randomName(),
@@ -51,46 +73,160 @@ class ImageTestCase extends DrupalWebTes
'files[image]' => realpath($this->image),
);
$this->drupalPost('node/add/image', $edit, t('Save'));
-
- $this->assertRaw(t('@type %title has been created.', array('@type' => 'Image', '%title' => $edit['title'])), t('Image created.'));
-
+
+ $this->assertRaw(t('@type %title has been created.', array('@type' => 'Image', '%title' => $edit['title'])), t('Image node was created.'));
+
$node = node_load(array('title' => $edit['title']));
- $this->assertTrue($node, t('Image found in database.'));
+ $this->assertTrue($node, t('Image node is found in database.'));
// Display an image.
+ $this->drupalGet('node/' . $node->nid, array('query' => 'size=_original'));
+ $this->assertPattern('@]+?' . $node->images['_original'] . '[^>]+?>@', t('Original image displayed on the page.'));
+ $this->assertTrue(file_exists($node->images['_original']), t('Original image exists.'));
+
$this->drupalGet('node/' . $node->nid);
$this->assertPattern('@]+?' . $node->images['preview'] . '[^>]+?>@', t('Image preview displayed on the page.'));
$this->assertTrue(file_exists($node->images['preview']), t('Image preview exists.'));
- $this->drupalGet('node/' . $node->nid, array('query' => 'size=_original'));
- $this->assertPattern('@]+?' . $node->images['_original'] . '[^>]+?>@', t('Original image displayed on the page.'));
- $this->assertTrue(file_exists($node->images['_original']), t('Original image exists.'));
-
$this->drupalGet('node/' . $node->nid, array('query' => 'size=thumbnail'));
$this->assertPattern('@]+?' . $node->images['thumbnail'] . '[^>]+?>@', t('Image thumbnail displayed on the page.'));
$this->assertTrue(file_exists($node->images['thumbnail']), t('Image thumbnail exists.'));
-
+
// Edit an image.
$another_edit = array(
'title' => $edit['title'],
'files[image]' => realpath($this->another_image),
);
- $this->drupalPost('node/' . $node->nid .'/edit', $another_edit, t('Save'));
+ $this->drupalPost('node/' . $node->nid . '/edit', $another_edit, t('Save'));
$another_node = node_load(array('title' => $edit['title']));
- $this->assertFalse(file_exists($node->images['preview']) || file_exists($node->images['_original']) || file_exists($node->images['thumbnail']), t('The previous image deleted.'));
-
+ $this->assertFalse(file_exists($node->images['preview']) || file_exists($node->images['_original']) || file_exists($node->images['thumbnail']), t('Previous image derivative files were deleted.'));
+
// Delete an image.
- $this->drupalPost('node/' . $node->nid .'/delete', array(), t('Delete'));
- $this->assertRaw(t('@type %title has been deleted.', array('@type' => 'Image', '%title' => $edit['title'])), t('Image created.'));
+ $this->drupalPost('node/' . $node->nid . '/delete', array(), t('Delete'));
+ $this->assertRaw(t('@type %title has been deleted.', array('@type' => 'Image', '%title' => $edit['title'])), t('Image node was deleted.'));
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertFalse($node, t('Image node is not found in database.'));
+ $this->assertFalse(file_exists($another_node->images['preview']) || file_exists($another_node->images['_original']) || file_exists($another_node->images['thumbnail']), t('Image file was deleted.'));
+ }
+
+ /**
+ * Verify that images cannot be created without a file.
+ */
+ function testImageNodeValidation() {
+ // Create an image node without image file.
+ $edit = array(
+ 'title' => $this->randomName(),
+ 'body' => $this->randomName(),
+ );
+ $this->drupalPost('node/add/image', $edit, t('Save'));
+ $this->assertRaw(t('You must upload an image.'), t('Refused node creation without image.'));
+
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertFalse($node, t('Image node is not found in database.'));
+ }
+
+ /**
+ * Verify image previews and proper submission.
+ */
+ function testImageNodePreview() {
+ // Setup POST data for image.
+ $edit = array(
+ 'title' => $this->randomName(),
+ 'body' => $this->randomName(),
+ 'files[image]' => realpath($this->image),
+ );
+
+ // Preview image node.
+ $this->drupalGet('node/add/image');
+ $this->drupalPost(NULL, $edit, t('Preview'));
+
+ // Save image node preview as is.
+ $this->drupalPost(NULL, NULL, t('Save'));
+
+ // Verify image node was properly created.
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertTrue($node, t('Image node is found in database.'));
+ $this->assertTrue(file_exists($node->images['_original']), t('Original image exists.'));
+ $filename = preg_replace('/_[^\.]+/', '', basename($node->images['_original']));
+ $this->assertTrue($filename == basename($this->image), t('Image file was properly stored.'));
+ }
+
+ /**
+ * Verify that images can be created in parallel (session handling).
+ *
+ * @todo Doesn't look valid. Can SimpleTest support this at all?
+ * @todo testImageCreateNodeFrom() fails is this test is run.
+ */
+ function __testImageNodeValidationAsync() {
+ // Setup POST data for first image.
+ $edit1 = array(
+ 'title' => $this->randomName(),
+ 'body' => $this->randomName(),
+ 'files[image]' => realpath($this->image),
+ );
+ // Setup POST data for second image.
+ $edit2 = array(
+ 'title' => $this->randomName(),
+ 'body' => $this->randomName(),
+ 'files[image]' => realpath($this->another_image),
+ );
+
+ // Preview the first image node.
+ $this->drupalGet('node/add/image');
+ $this->drupalPost(NULL, $edit1, t('Preview'));
+
+ // Preview the second image node.
+ $this->drupalGet('node/add/image');
+ $this->drupalPost(NULL, $edit2, t('Preview'));
+
+ // Save the first image node.
+ $this->drupalPost(NULL, $edit1, t('Save'));
+ // Save the second image node.
+ $this->drupalPost('node/add/image', $edit2, t('Save'));
+
+ // Verify first image node contains the first image.
+ $node = node_load(array('title' => $edit1['title']));
+ $filename = preg_replace('/_[^\.]+/', '', basename($node->images['_original']));
+ $this->assertTrue($filename == basename($this->image), t('First image was properly submitted.'));
+
+ // Verify second image node contains the second image.
+ $node = node_load(array('title' => $edit2['title']));
+ $filename = preg_replace('/_[^\.]+/', '', basename($node->images['_original']));
+ $this->assertTrue($filename == basename($this->another_image), t('Second image was properly submitted.'));
+ }
+
+ /**
+ * Verify that images with missing file information can be deleted from edit form.
+ */
+ function testImageNodeDeletion() {
+ // Create an image.
+ $edit = array(
+ 'title' => $this->randomName(),
+ 'body' => $this->randomName(),
+ 'files[image]' => realpath($this->image),
+ );
+
+ // Create image.
+ $this->drupalPost('node/add/image', $edit, t('Save'));
+ $this->assertRaw(t('@type %title has been created.', array('@type' => 'Image', '%title' => $edit['title'])), t('Image node was created.'));
$node = node_load(array('title' => $edit['title']));
- $this->assertFalse($node, t('Image not found in database.'));
- $this->assertFalse(file_exists($another_node->images['preview']) || file_exists($another_node->images['_original']) || file_exists($another_node->images['thumbnail']), t('Image deleted.'));
+ $this->assertTrue($node, t('Image node is found in database.'));
+
+ // Remove {files} row to create corruption condition.
+ $this->assertTrue(db_query("DELETE f FROM {files} f INNER JOIN {image} i WHERE f.fid = i.fid AND i.nid = %d", $node->nid), t('Image file information was deleted.'));
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertFalse(isset($node->images['_original']), t('Image file information is missing on re-loaded node.'));
+
+ $this->drupalPost('node/' . $node->nid . '/edit', array(), t('Delete'));
+ $this->assertRaw(t('Are you sure you want to delete %title?', array('%title' => $edit['title'])), t('Delete confirmation form is displayed.'));
+ $this->drupalPost(NULL, array(), t('Delete'));
+ $this->assertRaw(t('@type %title has been deleted.', array('@type' => 'Image', '%title' => $edit['title'])), t('Image node was deleted.'));
}
/**
- * Test image node creation.
+ * Verify image_create_node_from() works like regular image node creation.
*/
- function testCreateNode() {
+ function testImageCreateNodeFrom() {
$edit = array(
'title' => $this->randomName(),
'body' => $this->randomName(),
@@ -98,23 +234,28 @@ class ImageTestCase extends DrupalWebTes
);
$this->drupalPost('node/add/image', $edit, t('Save'));
$this->assertRaw(t('@type %title has been created.', array('@type' => 'Image', '%title' => $edit['title'])), t('Image created.'));
-
+
$node_post = node_load(array('title' => $edit['title']));
- $this->assertTrue($node_post, t('Image found in database.'));
+ $this->assertTrue($node_post, t('Form created image node found in database.'));
- // Make a copy of the image so image_create_node_from() deletes original image.
+ // Copy the image, since image_create_node_from() deletes the original image.
file_copy($edit['files[image]'], file_directory_temp());
$node_api = image_create_node_from(file_directory_temp() . '/' . basename($edit['files[image]']), $edit['title'], $edit['body']);
- // Rebuild images.
+ $this->assertTrue(is_object($node_api) && $node_api->nid, t('API created image node found in database.'));
+ // Rebuild derivative images.
$node_api = node_load($node_api->nid);
- // Check equality of nodes.
- $equality =
- ($node_post->title == $node_api->title) &&
- (strip_tags($node_post->body) == strip_tags($node_api->body)) &&
- (filesize($node_post->images['_original']) == filesize($node_api->images['_original'])) &&
- (filesize($node_post->images['preview']) == filesize($node_api->images['preview'])) &&
- (filesize($node_post->images['thumbnail']) == filesize($node_api->images['thumbnail']));
- $this->assertTrue($equality, t('Images nodes are equal.'));
+ // Verify that both nodes are equal.
+ $equality = ($node_post->title == $node_api->title);
+ $this->assertTrue($equality, t('Image node titles are equal.'));
+ $equality = $equality && (strip_tags($node_post->body) == strip_tags($node_api->body));
+ $this->assertTrue($equality, t('Image node bodys are equal.'));
+ $equality = $equality && (filesize($node_post->images['_original']) == filesize($node_api->images['_original']));
+ $this->assertTrue($equality, t('Original images are equal.'));
+ $equality = $equality && (filesize($node_post->images['preview']) == filesize($node_api->images['preview']));
+ $this->assertTrue($equality, t('Preview images are equal.'));
+ $equality = $equality && (filesize($node_post->images['thumbnail']) == filesize($node_api->images['thumbnail']));
+ $this->assertTrue($equality, t('Image nodes are equal.'));
}
}
+