I have an excel list of 600 users with name, email, and role - that I need to add to the drupal site I'm building.
There are 2 roles distributed among the users.
As an added complication, the site is using the Content Profile module, so it would be a great help if for each new user account created, a corresponding profile node was also auto-created.
Any ideas how to batch-create the new users?
How about the user_import module?
I had the same thing, and created a module for this.
Basically, it reads the user and what role to get from a file; in my case it was a CSV file with emailadres, name, role and stuff needed for the content profile.
Let's say you want user x#mail.com and fill out automatically his content profile data Name, Sirname and City or something.
In your module:
read the line from the file
create a new user
create a new node, (stdClass object, give it the correct type ('profile_data' or whatever your content profile type is) and fill the rest of yout node and save.
A sample:
<?php
//create a form with a button to read the CSV file
function bulk_users_submit() {
$users = 0;
$handle = fopen(drupal_get_path('module', 'bulk_users') .'/'.DATAFILE, "r");
if (!$handle) {
return $users;
}
while (($data = fgetcsv($handle)) !== FALSE) {
//this is similar to what the users.module does
if (bulk_users_create_user($data)) {
$users++;
bulk_users_create_profile($data);
}
}
fclose($handle);
return $users;
}
function bulk_users_create_profile($user, $data) {
$node = new stdClass();
$node->title = t('First and Last Name');
$node->body = "";
$node->type = 'first_and_last_name';
$node->created = time();
$node->changed = $node->created;
$node->status = 1;
$node->promote = 0;
$node->sticky = 0;
$node->format = 0;
$node->uid = $data['uid'];
$node->language = 'en';
$node->field_firstname[0]['value'] = $data['firstname'];
$node->field_lastname[0]['value'] = $data['lastname'];
node_save($node);
}
?>
not tested, but the idea is clear i hope.
Related
I am using Drupal's domain access module to create micro sites in a white label system. Is there a way of automatically creating nodes with default content for each site?
Use hook_domain_insert() this will give you the id of the domain that has just been created in the $domain array. Then you can create a node as follows:
function YOUR_MODULE_domain_insert($domain, $form_values = array()) {
$domain_id = $domain['domain_id'];
$node = new stdClass();
$node->type = 'your_type';
$node->title = 'Your Title';
node_object_prepare($node);
$node->language = LANGUAGE_NONE;
$node->domain_site = 0;
$node->domains[$domain_id] = $domain_id;
$node = node_submit($node);
node_save($node);
}
I'm using the feeds module to pull in a set of publications into a Drupal content type. They are set to run at regular intervals using cron. I have two separate feeds, which should work as follows:
Feed 1 (pure_feed) - pulls in the bulk of the fields
Feed 2 (harvard_format) - accesses a separate url source and updates one field on the content type.
The problem I have is that feed 2 always creates a new set of nodes rather than updating the existing nodes (that were created using feed 1). I have used the debug options at /import and can see that the GUIDs for feed 2 match the GUIDs for feed 1, but it still creates 2 sets of nodes rather than updating the 1 set of nodes.
Here is an excerpt from the feeds_items database table:
As you can see they both have the same GUID but they are mapped to separate nodes. Is there any way to have the second feed map to the same nodes as the first feed?
I knocked something together that allows my second feed to update the nodes from my first feed. Not sure if this is the right way of doing things but it works. Here's what I did in case it helps someone else in future:
Created a custom processor that extends FeedsNodeProcessor
Copied across all of FeedsNodeProcessor's functions to the new class.
Overrided the existingEntityId function as follows (harvard_format is my secondary feed and pure_feed is my primary feed):
protected function existingEntityId(FeedsSource $source, FeedsParserResult $result) {
if($source->id == 'harvard_format') {
$query = db_select('feeds_item')
->fields('feeds_item', array('entity_id'))
->condition('feed_nid', $source->feed_nid)
->condition('entity_type', $this->entityType())
->condition('id', 'pure_feed');
// Iterate through all unique targets and test whether they do already
// exist in the database.
foreach ($this->uniqueTargets($source, $result) as $target => $value) {
switch ($target) {
case 'url':
$entity_id = $query->condition('url', $value)->execute()->fetchField();
break;
case 'guid':
$entity_id = $query->condition('guid', $value)->execute()->fetchField();
break;
}
if (isset($entity_id)) {
// Return with the content id found.
return $entity_id;
}
}
return 0;
}
elseif ($nid = parent::existingEntityId($source, $result)) {
return $nid;
} else {
// Iterate through all unique targets and test whether they do already
// exist in the database.
foreach ($this->uniqueTargets($source, $result) as $target => $value) {
switch ($target) {
case 'nid':
$nid = db_query("SELECT nid FROM {node} WHERE nid = :nid", array(':nid' => $value))->fetchField();
break;
case 'title':
$nid = db_query("SELECT nid FROM {node} WHERE title = :title AND type = :type", array(':title' => $value, ':type' => $this->config['content_type']))->fetchField();
break;
case 'feeds_source':
if ($id = feeds_get_importer_id($this->config['content_type'])) {
$nid = db_query("SELECT fs.feed_nid FROM {node} n JOIN {feeds_source} fs ON n.nid = fs.feed_nid WHERE fs.id = :id AND fs.source = :source", array(':id' => $id, ':source' => $value))->fetchField();
}
break;
}
if ($nid) {
// Return with the first nid found.
return $nid;
}
}
return 0;
}
}
Copied across the the Process and newItemInfo functions from FeedsProcessor.
Overrided newItemInfo as follows:
protected function newItemInfo($entity, $feed_nid, $hash = '') {
$entity->feeds_item = new stdClass();
$entity->feeds_item->entity_id = 0;
$entity->feeds_item->entity_type = $this->entityType();
// Specify the feed id, otherwise pure_feed's entries in the feeds_item table will be changed to harvard_format
$entity->feeds_item->id = ($this->id == "harvard_format") ? "pure_feed" : $this->id;
$entity->feeds_item->feed_nid = $feed_nid;
$entity->feeds_item->imported = REQUEST_TIME;
$entity->feeds_item->hash = $hash;
$entity->feeds_item->url = '';
$entity->feeds_item->guid = '';
}
I am grabbing a file using CURL, and want to save it locally, but so it plugs into Drupal's file system. Would I have to do a manual insert or is there a better way? The closest I could find was:
function image_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items);
But I don't know how to use this. Any better suggestions?
There are a couple of ways but the easiest would be to use file_save_upload():
$source = '/path/to/file.ext';
$dest = 'public://uploads/'; // Or whatever
$file = file_save_upload($source, array(), $dest, FILE_EXISTS_RENAME);
if ($file) {
// file_save_upload marks the file as temporary, we need to mark as permanent or it will be cleared from the database in a few hours
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
}
This just about drove me out of my mind and in trying to figure out a simple way to circumvent the form API expectations I came across this question. Clive's answer was the beginning of how I figured it out because it looks like you can provide a source as the first arg for file_save_upload() but as it turns out, you cannot. At least not in the current drupal 7.30.
I checked the link he provided and deconstructed the function. Basically, even if you pass a full source path it still looks for the first arg in the $_FILES array way down the path. Who knows why, but what a dumb idea. So I did this:
//after verifying all post fields are set...
$node = new stdClass();
$node->type = 'user_files';
node_object_prepare($node);
$node->title = $_POST['title'];
$node->author = 2; //hardcoded because only admin uses this form
$node->uid = 2;
$node->language = LANGUAGE_NONE;
$node->body[$node->language][0]['value'] = $_POST['body'];
$node->body[$node->language][0]['summary'] = text_summary($_POST['body']);
$node->body[$node->language][0]['format'] = 'filtered_html';
$node->field_first_name[$node->language][0]['value'] = $_POST['first_name'];
$node->field_last_name[$node->language][0]['value'] = $_POST['last_name'];
node_save($node);
if(isset($_FILES['file']['tmp_name']) && $_FILES['file']['name'] != '')
{
//upload file
$file = new stdClass();
$file->uid = 2;
$file->status = 0;
$file->filename = trim(drupal_basename($_FILES['file']['name']), '.');
$file->uri = $_FILES['file']['name'];
$file->filemime = file_get_mimetype($file->filename);
$file->filesize = $_FILES['file']['size'];
$file->filename = file_munge_filename($file->filename, 'jpg jpeg gif png doc docx pdf');
$file->destination = file_destination('private://' . $file->filename, FILE_EXISTS_RENAME);
$file->uri = $file->destination;
if (!drupal_move_uploaded_file($_FILES['file']['tmp_name'], $file->uri)) {
return false; //set errors or do whatever you want on error
}
else
{
drupal_chmod($file->uri);
$existing_files = file_load_multiple(array(), array('uri' => $file->uri));
if (count($existing_files)) {
$existing = reset($existing_files);
$file->fid = $existing->fid;
}
if ($file = file_save($file)) {
// Add file to the cache.
$node->field_file[$node->language][0]['uri'] = 'private://'.$file->filename;
$node->field_file[$node->language][0]['fid'] = $file->fid;
$node->field_file[$node->language][0]['display'] = 1;
$node->field_file[$node->language][0]['description'] = 'User uploaded file';
node_save($node);
//do we notify someone?
}
}
}
What this does is creates a node of a specified type. In this case, user_files, then if a file is uploaded, add the file to the media table, or file table or whatever it's called. Then adds the association to the newly created node.
Is it ugly? Yeah. Why didn't I use the internal drupal form API? Shut up, that's why. We don't always have a choice, so when a client asks for a basic form that just emails them, it is quick and easy to make a simple field that sends through a mail chimp API or something. Then later they add that they want files. Then later they want it to add to the drupal back end and suddenly you have a snowball of horror that would have been a lot easier if it was done with the form API to begin with. I don't know who started it, but I had to end it and I did it with this ghastly hack. Hope it helps you or whoever else is currently spinning in the drupal vortex of horror.
I was able to do the following to add a file from the public:// Drupal folder (typically sites/default/files or sites/DOMAIN/files) using file_save.
$uri = 'public://filename.pdf';
$file = file_save((object) array(
'filename' => basename($uri),
'uri' => $uri,
'status' => FILE_STATUS_PERMANENT,
'filemime' => file_get_mimetype($uri),
));
This adds the appropriate entry into the Drupal core file_managed table. If you have the File Entity module installed, an entry is created there as well.
The returned file object will include the database ID as $file->fid.
I have a D7 website where users can make content (obviously...). So every node has it's own author. Every author is a member of an organization. But he can be a member of more then one organization. So far the facts.
I would like to create a view where the content is filtered on Author. Very easy, set the relation of the view on "Content's Author" and select the current user as filter.
But what I would like is to filter on the author's organization. So in fact it's a nested relation. Filter the nodes on the current logged in user (that's easy), but how can I filter on the current logged in user's organization?
Ok, the panels didn't work out, so I wrote my own hook :-)
function mymodule_views_pre_view (&$view, &$display_id, &$args) {
// Only execute this script when the view 'fiches_my_thema' is called
if ('fiches_my_thema' == $view->name) {
// Get users thema
global $user;
$userRoles = $user->roles;
$user_themas = array();
// Filter roles so you end up with the "Thema's".
foreach ($userRoles as $key) {
if(strpos($key,'edacteur')) {
$key = str_replace('Redacteur - ','', $key);
$key = str_replace('Eindredacteur - ','', $key);
$user_themas[] = $key;
}
}
// Resolve tid
$terms = taxonomy_get_tree(5);
$allRoles = array();
$arguments = array();
// Assign the 'tid' to a variable
foreach ($terms as $key) {
$singleRoles = $key->name;
$allRoles[] = $singleRoles;
if(in_array($singleRoles, $user_themas)) {
$arguments[] = $key->tid;
}
}
// Only when the arguments are NOT empty, set the arguments
if(!empty($arguments)) {
$finalArguments = implode("+", $arguments);
$args[] = "$finalArguments";
$view->set_arguments($args);
}
}
}
Is there a way for me to do the following:
Create a new content object of type 'A':
//The global user is user Y
$node = new Object();
$node->type = 'A'
//etc..
//Save node - but I want the node to look like it was created by user X
node_save($node);
This is a case where user Y does not have 'create A content' permission, but user X does and all content of type A should be created by user X (i.e. the script);
From Safely Impersonating Another User in the Drupal manual:
<?php
global $user;
$original_user = $user;
session_save_session(FALSE); // D7: use drupal_save_session(FALSE);
$user = user_load(array('uid' => 1)); // D7: use user_load(1);
// DO YOUR STUFF HERE, for example node_save($node);
// If your code fails, it's not a problem because the session will not be saved
$user = $original_user;
session_save_session(TRUE); // // D7: use drupal_save_session(TRUE);
// From here on the $user is back to normal so it's OK for the session to be saved
?>