diff --git a/css/redactor.css b/css/redactor.css index e6d048dba9eec977e538f1ecd8f5992d8e02539d..052eec5b37c1de720864bbc5561917c0089ca744 100644 --- a/css/redactor.css +++ b/css/redactor.css @@ -153,6 +153,7 @@ body .redactor-box-fullscreen { background: #fff; border: none; box-shadow: 0 1px 4px -2px rgba(0, 0, 0, 0.4); + z-index: 1 !important; } .redactor-toolbar:after { content: ""; diff --git a/include/ajax.forms.php b/include/ajax.forms.php index 37f6399ff80943bfc8056855c61d797cf813fd7b..1d4dc14236ad922978c8cefd7e8020bc1a6d14da 100644 --- a/include/ajax.forms.php +++ b/include/ajax.forms.php @@ -208,7 +208,7 @@ class DynamicFormsAjaxAPI extends AjaxController { 'value' => $I->getValue(), 'display' => $display, 'id' => $I->id, - 'list_id' => $I->getList()->getId(), + 'list_id' => $list->getId(), ); } return $this->encode($results); @@ -260,15 +260,16 @@ class DynamicFormsAjaxAPI extends AjaxController { 'title' => sprintf('%s — %s', $list->getName(), __('Import Items')), 'action' => "#list/{$list_id}/import", - 'upload_url' => "lists.php?id={$list_id}&do=import-users", + 'upload_url' => "lists.php?id={$list_id}&do=import-items", ); if ($_POST) { - $status = $list->importFromPost($_POST['pasted']); - if (is_string($status)) - $info['error'] = $status; - else - Http::response(201, $this->encode(array('success' => true, 'count' => $status))); + $status = $list->importFromPost($_FILES['import'] ?: $_POST['pasted']); + if ($status && is_numeric($status)) + Http::response(201, $this->encode( array('success' => true, 'count' => $status))); + + $info['error'] = $status; + $info['pasted'] = Format::htmlchars($_POST['pasted']); } include(STAFFINC_DIR . 'templates/list-import.tmpl.php'); diff --git a/include/class.import.php b/include/class.import.php index c128136b7439845714435a503f89ed131609e0bd..dc9a027c1d4af5606a6f9f2df293f9e097d5b72f 100644 --- a/include/class.import.php +++ b/include/class.import.php @@ -84,7 +84,8 @@ class CsvImporter { break; } else { - throw new ImportError(sprintf(__('%s: Unable to map header to a user field'), $h)); + throw new ImportError(sprintf( + __('%s: Unable to map header to the object field'), $h)); } } } diff --git a/include/class.list.php b/include/class.list.php index bd6ed087eff317ab6cc26507f626f4ef7b24fea7..f2b1b1301c028356dfe5db0050676520358c70a6 100644 --- a/include/class.list.php +++ b/include/class.list.php @@ -523,11 +523,11 @@ class DynamicList extends VerySimpleModel implements CustomList { return $selections; } - function importCsv($stream, $defaults=array()) { - //Read the header (if any) - $headers = array('value' => __('Value'), 'abbrev' => __('Abbreviation')); + function importCsv($stream, $defaults=array()) { + require_once INCLUDE_DIR . 'class.import.php'; + $form = $this->getConfigurationForm(); - $named_fields = $fields = array( + $fields = array( 'value' => new TextboxField(array( 'label' => __('Value'), 'name' => 'value', @@ -536,119 +536,42 @@ class DynamicList extends VerySimpleModel implements CustomList { ), )), 'abbrev' => new TextboxField(array( - 'name' => 'abbrev', + 'name' => 'extra', 'label' => __('Abbreviation'), 'configuration' => array( 'length' => 0, ), )), ); - $all_fields = $form->getFields(); - $has_header = false; - foreach ($all_fields as $f) - if ($f->get('name')) - $named_fields[] = $f; - - if (!($data = fgetcsv($stream, 1000, ","))) - return __('Whoops. Perhaps you meant to send some CSV records'); - - foreach ($data as $D) { - if (strcasecmp($D, 'value') === 0) - $has_header = true; - } - if ($has_header) { - foreach ($data as $h) { - $found = false; - foreach ($all_fields as $f) { - if (in_array(mb_strtolower($h), array( - mb_strtolower($f->get('name')), mb_strtolower($f->get('label'))))) { - $found = true; - if (!$f->get('name')) - return sprintf(__( - '%s: Field must have `variable` set to be imported'), $h); - $headers[$f->get('name')] = $f->get('label'); - break; - } - } - if (!$found) { - $has_header = false; - if (count($data) == count($named_fields)) { - // Number of fields in the user form matches the number - // of fields in the data. Assume things line up - $headers = array(); - foreach ($named_fields as $f) - $headers[$f->get('name')] = $f->get('label'); - break; - } - else { - return sprintf(__('%s: Unable to map header to a property'), $h); - } - } - } - } - - // 'value' MUST be in the headers - if (!isset($headers['value'])) - return __('CSV file must include `value` column'); - - if (!$has_header) - fseek($stream, 0); - $items = array(); - $keys = array('value', 'abbrev'); - foreach ($headers as $h => $label) { - if (!($f = $form->getField($h))) - continue; - - $name = $keys[] = $f->get('name'); - $fields[$name] = $f->getImpl(); - } - - // Add default fields (org_id, etc). - foreach ($defaults as $key => $val) { - // Don't apply defaults which are also being imported - if (isset($header[$key])) - unset($defaults[$key]); - $keys[] = $key; + $form = $this->getConfigurationForm(); + if ($form && ($custom_fields = $form->getFields()) + && count($custom_fields)) { + foreach ($custom_fields as $f) + if ($f->get('name')) + $fields[$f->get('name')] = $f; } - while (($data = fgetcsv($stream, 1000, ",")) !== false) { - if (count($data) == 1 && $data[0] == null) - // Skip empty rows - continue; - elseif (count($data) != count($headers)) - return sprintf(__('Bad data. Expected: %s'), implode(', ', $headers)); - // Validate according to field configuration - $i = 0; - foreach ($headers as $h => $label) { - $f = $fields[$h]; - $T = $f->parse($data[$i]); - if ($f->validateEntry($T) && $f->errors()) - return sprintf(__( - /* 1 will be a field label, and 2 will be error messages */ - '%1$s: Invalid data: %2$s'), - $label, implode(', ', $f->errors())); - // Convert to database format - $data[$i] = $f->to_database($T); - $i++; + $importer = new CsvImporter($stream); + $imported = 0; + try { + db_autocommit(false); + $records = $importer->importCsv($fields, $defaults); + foreach ($records as $data) { + $errors = array(); + $item = $this->addItem($data, $errors); + if ($item && $item->setConfiguration($data, $errors)) + $imported++; + else + echo sprintf(__('Unable to import item: %s'), print_r($data, true)); } - // Add default fields - foreach ($defaults as $key => $val) - $data[] = $val; - - $items[] = $data; + db_autocommit(true); } - - foreach ($items as $u) { - $vars = array_combine($keys, $u); - $errors = array(); - $item = $this->addItem($vars, $errors); - if (!$item || !$item->setConfiguration($vars, $errors)) - return sprintf(__('Unable to import item: %s'), - print_r($vars, true)); + catch (Exception $ex) { + db_rollback(); + return $ex->getMessage(); } - - return count($items); + return $imported; } function importFromPost($stuff, $extra=array()) { diff --git a/scp/lists.php b/scp/lists.php index c5a552f3e17dfbe78de5f09c6c089f967092e8f8..6ec0fdc9259b5710144f9dfa131f46293832ce44 100644 --- a/scp/lists.php +++ b/scp/lists.php @@ -25,7 +25,7 @@ if ($criteria) { $errors = array(); if($_POST) { - switch(strtolower($_POST['do'])) { + switch(strtolower($_REQUEST['do'])) { case 'update': if (!$list) $errors['err']=sprintf(__('%s: Unknown or invalid ID.'),