summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/FeedsNodeProcessor.inc40
-rwxr-xr-x[-rw-r--r--]plugins/FeedsProcessor.inc20
-rw-r--r--tests/feeds_processor_node.test53
3 files changed, 110 insertions, 3 deletions
diff --git a/plugins/FeedsNodeProcessor.inc b/plugins/FeedsNodeProcessor.inc
index b80953b..d208047 100644
--- a/plugins/FeedsNodeProcessor.inc
+++ b/plugins/FeedsNodeProcessor.inc
@@ -78,6 +78,39 @@ class FeedsNodeProcessor extends FeedsProcessor {
}
/**
+ * Check that the user has permission to save a node.
+ */
+ protected function entitySaveAccess($entity) {
+
+ // The check will be skipped for anonymous nodes.
+ if ($this->config['authorize'] && !empty($entity->uid)) {
+
+ $author = user_load($entity->uid);
+
+ // If the uid was mapped directly, rather than by email or username, it
+ // could be invalid.
+ if (!$author) {
+ $message = 'User %uid is not a valid user.';
+ throw new FeedsAccessException(t($message, array('%uid' => $entity->uid)));
+ }
+
+ if (empty($entity->nid) || !empty($entity->is_new)) {
+ $op = 'create';
+ $access = node_access($op, $entity->type, $author);
+ }
+ else {
+ $op = 'update';
+ $access = node_access($op, $entity, $author);
+ }
+
+ if (!$access) {
+ $message = 'User %name is not authorized to %op content type %content_type.';
+ throw new FeedsAccessException(t($message, array('%name' => $author->name, '%op' => $op, '%content_type' => $entity->type)));
+ }
+ }
+ }
+
+ /**
* Save a node.
*/
public function entitySave($entity) {
@@ -137,6 +170,7 @@ class FeedsNodeProcessor extends FeedsProcessor {
'content_type' => $type,
'expire' => FEEDS_EXPIRE_NEVER,
'author' => 0,
+ 'authorize' => TRUE,
) + parent::configDefaults();
}
@@ -162,6 +196,12 @@ class FeedsNodeProcessor extends FeedsProcessor {
'#autocomplete_path' => 'user/autocomplete',
'#default_value' => empty($author->name) ? 'anonymous' : check_plain($author->name),
);
+ $form['authorize'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Authorize'),
+ '#description' => t('Check that the author has permission to create the node.'),
+ '#default_value' => $this->config['authorize'],
+ );
$period = drupal_map_assoc(array(FEEDS_EXPIRE_NEVER, 3600, 10800, 21600, 43200, 86400, 259200, 604800, 2592000, 2592000 * 3, 2592000 * 6, 31536000), 'feeds_format_expire');
$form['expire'] = array(
'#type' => 'select',
diff --git a/plugins/FeedsProcessor.inc b/plugins/FeedsProcessor.inc
index 31d30b1..80e54d5 100644..100755
--- a/plugins/FeedsProcessor.inc
+++ b/plugins/FeedsProcessor.inc
@@ -20,6 +20,11 @@ define('FEEDS_PROCESS_LIMIT', 50);
class FeedsValidationException extends Exception {}
/**
+ * Thrown if a an access check fails.
+ */
+class FeedsAccessException extends Exception {}
+
+/**
* Abstract class, defines interface for processors.
*/
abstract class FeedsProcessor extends FeedsPlugin {
@@ -65,10 +70,21 @@ abstract class FeedsProcessor extends FeedsPlugin {
protected function entityValidate($entity) {}
/**
+ * Access check for saving an enity.
+ *
+ * @param $entity
+ * Entity to be saved.
+ *
+ * @throws FeedsAccessException $e
+ * If the access check fails.
+ */
+ protected function entitySaveAccess($entity) {}
+
+ /**
* Save an entity.
*
* @param $entity
- * Entity to b saved.
+ * Entity to be saved.
*/
protected abstract function entitySave($entity);
@@ -159,6 +175,8 @@ abstract class FeedsProcessor extends FeedsPlugin {
continue;
}
+ // This will throw an exception on failure.
+ $this->entitySaveAccess($entity);
$this->entitySave($entity);
// Track progress.
diff --git a/tests/feeds_processor_node.test b/tests/feeds_processor_node.test
index 7e1b8d6..677bd95 100644
--- a/tests/feeds_processor_node.test
+++ b/tests/feeds_processor_node.test
@@ -144,9 +144,9 @@ class FeedsRSStoNodesTest extends FeedsWebTestCase {
$this->assertText('Deleted 10 nodes');
$this->assertFeedItemCount(0);
- // Change author.
+ // Change author and turn off authorization.
$this->auth_user = $this->drupalCreateUser(array('access content'));
- $this->setSettings('syndication', 'FeedsNodeProcessor', array('author' => $this->auth_user->name));
+ $this->setSettings('syndication', 'FeedsNodeProcessor', array('author' => $this->auth_user->name, 'authorize' => FALSE));
// Change input format.
$this->setSettings('syndication', 'FeedsNodeProcessor', array('input_format' => 'plain_text'));
@@ -406,4 +406,53 @@ class FeedsRSStoNodesTest extends FeedsWebTestCase {
$this->drupalGet('node/add/article');
$this->assertNoFieldByName('feeds[FeedsHTTPFetcher][source]');
}
+
+ /**
+ * Test that nodes will not be created if the user is unauthorized to create
+ * them.
+ */
+ public function testAuthorize() {
+
+ // Create a user with limited permissions. We can't use
+ // $this->drupalCreateUser here because we need to to set a specific user
+ // name.
+ $edit = array(
+ 'name' => 'Development Seed',
+ 'mail' => 'devseed@example.com',
+ 'pass' => user_password(),
+ 'status' => 1,
+ );
+
+ $account = user_save(drupal_anonymous_user(), $edit);
+
+ // Adding a mapping to the user_name will invoke authorization.
+ $this->addMappings('syndication',
+ array(
+ 5 => array(
+ 'source' => 'author_name',
+ 'target' => 'user_name',
+ ),
+ )
+ );
+
+ $nid = $this->createFeedNode();
+
+ $this->assertText('Failed importing 10 nodes.');
+ $this->assertText('User ' . $account->name . ' is not authorized to create content type article.');
+ $node_count = db_query("SELECT COUNT(*) FROM {node}")->fetchField();
+
+ // We should have 1 node, the feed node.
+ $this->assertEqual($node_count, 1, t('Correct number of nodes in the database.'));
+
+ // Give the user our admin powers.
+ $edit = array(
+ 'roles' => $this->admin_user->roles,
+ );
+ $account = user_save($account, $edit);
+
+ $this->drupalPost("node/$nid/import", array(), 'Import');
+ $this->assertText('Created 10 nodes.');
+ $node_count = db_query("SELECT COUNT(*) FROM {node}")->fetchField();
+ $this->assertEqual($node_count, 11, t('Correct number of nodes in the database.'));
+ }
}