FeedsUserProcessor.inc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. <?php
  2. /**
  3. * @file
  4. * Contains FeedsUserProcessor.
  5. */
  6. /**
  7. * Option to block users not found in the feed.
  8. *
  9. * @var string
  10. */
  11. define('FEEDS_BLOCK_NON_EXISTENT', 'block');
  12. /**
  13. * Feeds processor plugin. Create users from feed items.
  14. */
  15. class FeedsUserProcessor extends FeedsProcessor {
  16. /**
  17. * Define entity type.
  18. */
  19. public function entityType() {
  20. return 'user';
  21. }
  22. /**
  23. * Implements parent::entityInfo().
  24. */
  25. protected function entityInfo() {
  26. $info = parent::entityInfo();
  27. $info['label plural'] = t('Users');
  28. return $info;
  29. }
  30. /**
  31. * Creates a new user account in memory and returns it.
  32. */
  33. protected function newEntity(FeedsSource $source) {
  34. $account = parent::newEntity($source);
  35. $account->uid = 0;
  36. $account->roles = array_filter($this->config['roles']);
  37. $account->status = $this->config['status'];
  38. return $account;
  39. }
  40. /**
  41. * Loads an existing user.
  42. */
  43. protected function entityLoad(FeedsSource $source, $uid) {
  44. $user = parent::entityLoad($source, $uid);
  45. // Copy the password so that we can compare it again at save.
  46. $user->feeds_original_pass = $user->pass;
  47. return $user;
  48. }
  49. /**
  50. * Validates a user account.
  51. */
  52. protected function entityValidate($account) {
  53. parent::entityValidate($account);
  54. if (empty($account->name) || empty($account->mail) || !valid_email_address($account->mail)) {
  55. throw new FeedsValidationException(t('User name missing or email not valid.'));
  56. }
  57. }
  58. /**
  59. * Save a user account.
  60. */
  61. protected function entitySave($account) {
  62. if ($this->config['defuse_mail']) {
  63. $account->mail = $account->mail . '_test';
  64. }
  65. $edit = (array) $account;
  66. // Remove pass from $edit if the password is unchanged.
  67. if (isset($account->feeds_original_pass) && $account->pass == $account->feeds_original_pass) {
  68. unset($edit['pass']);
  69. }
  70. user_save($account, $edit);
  71. if ($account->uid && !empty($account->openid)) {
  72. $authmap = array(
  73. 'uid' => $account->uid,
  74. 'module' => 'openid',
  75. 'authname' => $account->openid,
  76. );
  77. if (SAVED_UPDATED != drupal_write_record('authmap', $authmap, array('uid', 'module'))) {
  78. drupal_write_record('authmap', $authmap);
  79. }
  80. }
  81. }
  82. /**
  83. * Delete multiple user accounts.
  84. */
  85. protected function entityDeleteMultiple($uids) {
  86. user_delete_multiple($uids);
  87. }
  88. /**
  89. * Override parent::configDefaults().
  90. */
  91. public function configDefaults() {
  92. return array(
  93. 'roles' => array(),
  94. 'status' => 1,
  95. 'defuse_mail' => FALSE,
  96. ) + parent::configDefaults();
  97. }
  98. /**
  99. * Override parent::configForm().
  100. */
  101. public function configForm(&$form_state) {
  102. $form = parent::configForm($form_state);
  103. $form['status'] = array(
  104. '#type' => 'radios',
  105. '#title' => t('Status'),
  106. '#description' => t('Select whether users should be imported active or blocked.'),
  107. '#options' => array(0 => t('Blocked'), 1 => t('Active')),
  108. '#default_value' => $this->config['status'],
  109. );
  110. $roles = user_roles(TRUE);
  111. unset($roles[2]);
  112. if (count($roles)) {
  113. $form['roles'] = array(
  114. '#type' => 'checkboxes',
  115. '#title' => t('Additional roles'),
  116. '#description' => t('Every user is assigned the "authenticated user" role. Select additional roles here.'),
  117. '#default_value' => $this->config['roles'],
  118. '#options' => $roles,
  119. );
  120. }
  121. $form['defuse_mail'] = array(
  122. '#type' => 'checkbox',
  123. '#title' => t('Defuse e-mail addresses'),
  124. '#description' => t('This appends _test to all imported e-mail addresses to ensure they cannot be used as recipients.'),
  125. '#default_value' => $this->config['defuse_mail'],
  126. );
  127. $form['update_non_existent']['#options'][FEEDS_BLOCK_NON_EXISTENT] = t('Block non-existent users');
  128. return $form;
  129. }
  130. /**
  131. * Override setTargetElement to operate on a target item that is a node.
  132. */
  133. public function setTargetElement(FeedsSource $source, $target_user, $target_element, $value) {
  134. switch ($target_element) {
  135. case 'created':
  136. $target_user->created = feeds_to_unixtime($value, REQUEST_TIME);
  137. break;
  138. case 'language':
  139. $target_user->language = strtolower($value);
  140. break;
  141. default:
  142. parent::setTargetElement($source, $target_user, $target_element, $value);
  143. break;
  144. }
  145. }
  146. /**
  147. * Return available mapping targets.
  148. */
  149. public function getMappingTargets() {
  150. $targets = parent::getMappingTargets();
  151. $targets += array(
  152. 'name' => array(
  153. 'name' => t('User name'),
  154. 'description' => t('Name of the user.'),
  155. 'optional_unique' => TRUE,
  156. ),
  157. 'mail' => array(
  158. 'name' => t('Email address'),
  159. 'description' => t('Email address of the user.'),
  160. 'optional_unique' => TRUE,
  161. ),
  162. 'created' => array(
  163. 'name' => t('Created date'),
  164. 'description' => t('The created (e. g. joined) data of the user.'),
  165. ),
  166. 'pass' => array(
  167. 'name' => t('Unencrypted Password'),
  168. 'description' => t('The unencrypted user password.'),
  169. ),
  170. 'status' => array(
  171. 'name' => t('Account status'),
  172. 'description' => t('Whether a user is active or not. 1 stands for active, 0 for blocked.'),
  173. ),
  174. 'language' => array(
  175. 'name' => t('User language'),
  176. 'description' => t('Default language for the user.'),
  177. ),
  178. );
  179. if (module_exists('openid')) {
  180. $targets['openid'] = array(
  181. 'name' => t('OpenID identifier'),
  182. 'description' => t('The OpenID identifier of the user. <strong>CAUTION:</strong> Use only for migration purposes, misconfiguration of the OpenID identifier can lead to severe security breaches like users gaining access to accounts other than their own.'),
  183. 'optional_unique' => TRUE,
  184. );
  185. }
  186. $this->getHookTargets($targets);
  187. return $targets;
  188. }
  189. /**
  190. * Get id of an existing feed item term if available.
  191. */
  192. protected function existingEntityId(FeedsSource $source, FeedsParserResult $result) {
  193. if ($uid = parent::existingEntityId($source, $result)) {
  194. return $uid;
  195. }
  196. // Iterate through all unique targets and try to find a user for the
  197. // target's value.
  198. foreach ($this->uniqueTargets($source, $result) as $target => $value) {
  199. switch ($target) {
  200. case 'name':
  201. $uid = db_query("SELECT uid FROM {users} WHERE name = :name", array(':name' => $value))->fetchField();
  202. break;
  203. case 'mail':
  204. $uid = db_query("SELECT uid FROM {users} WHERE mail = :mail", array(':mail' => $value))->fetchField();
  205. break;
  206. case 'openid':
  207. $uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname AND module = 'openid'", array(':authname' => $value))->fetchField();
  208. break;
  209. }
  210. if ($uid) {
  211. // Return with the first nid found.
  212. return $uid;
  213. }
  214. }
  215. return 0;
  216. }
  217. /**
  218. * Overrides FeedsProcessor::clean().
  219. *
  220. * Block users instead of deleting them.
  221. *
  222. * @param FeedsState $state
  223. * The FeedsState object for the given stage.
  224. */
  225. protected function clean(FeedsState $state) {
  226. // Delegate to parent if not blocking or option not set.
  227. if (!isset($this->config['update_non_existent']) || $this->config['update_non_existent'] !== FEEDS_BLOCK_NON_EXISTENT) {
  228. return parent::clean($state);
  229. }
  230. if (!empty($state->removeList)) {
  231. // @see user_user_operations_block().
  232. // The following foreach is copied from above function but with an added
  233. // counter to count blocked users.
  234. foreach (user_load_multiple($state->removeList) as $account) {
  235. $this->loadItemInfo($account);
  236. $account->feeds_item->hash = $this->config['update_non_existent'];
  237. // For efficiency manually save the original account before applying any
  238. // changes.
  239. $account->original = clone $account;
  240. user_save($account, array('status' => 0));
  241. $state->blocked++;
  242. }
  243. }
  244. }
  245. }