Project

General

Profile

Download (15.6 KB) Statistics
| Branch: | Tag: | Revision:
1 9c7f9ab7 Andreas Kohlbecker
<?php
2
3 dc70e39a n.hoffmann
// at the moment we are using a static meta.xml file
4 e3d8e63e n.hoffmann
define ("METADATA_FILE_NAME", "meta.xml");
5
define ("STATIC_DIR", "/static/");
6 dc70e39a n.hoffmann
define ("ARCHIVE_ROOT_DIR", "dwca_export/");
7 fee09cdd l.morris
define ('FILE_MAP', 'dwca_export_archive_descriptor_file_map');
8 53643c8a l.morris
define ('FILE_EXTENSION', ".txt");
9 dc70e39a n.hoffmann
10 f6086da6 l.morris
//$view_all_names_except_description = array('classification', 'specimen', 'reference', 'image', 'distribution');
11
12 dc70e39a n.hoffmann
13 9c7f9ab7 Andreas Kohlbecker
/**
14
 * Implements hook_menu().
15
 */
16
function dwca_export_menu() {
17
18
	$items = array();
19
20 3ac1e968 Andreas Kohlbecker
	$items['admin/config/system/dwca_export'] = array(
21
		'title' => 'Darwin Core Archive export',
22 1e97110c n.hoffmann
		'description' => t('Create a DarwinCore Archive of this scratchpad.'),
23 9c7f9ab7 Andreas Kohlbecker
		'page callback' => 'drupal_get_form',
24
		'page arguments' => array('dwca_export_config_form'),
25 1e97110c n.hoffmann
		'access arguments' => array('access DwC-A export settings'),
26 3ac1e968 Andreas Kohlbecker
		'type' => MENU_NORMAL_ITEM,
27 9c7f9ab7 Andreas Kohlbecker
		//'file' => 'dwca_export.admin.inc'
28
	);
29
30 ab2258a1 l.morris
31 9c7f9ab7 Andreas Kohlbecker
	$items['dwca_export'] = array(
32
		'page callback' => 'dwca_export_deliver_archive',
33 6ab7ce86 Andreas Kohlbecker
		'access arguments' => array('access content'),
34 9c7f9ab7 Andreas Kohlbecker
		'type' => MENU_CALLBACK
35
	);
36
37
38
	return $items;
39
}
40
41 f6086da6 l.morris
function dwca_export_view_names_array(){
42
43
	$view_names = array('classification', 'specimen', 'reference', 'image', 'distribution');
44
45
	return $view_names;
46
}
47
48 d0c09d70 Andreas Kohlbecker
/**
49
 * Implementation of hook_views_api()
50
 *
51
 * drupal will load dwca_export.views_default.inc when this hook is implemented
52
 */
53
function dwca_export_views_api() {
54 7156bdbf n.hoffmann
	return array(
55
		'api' => 3.0
56
	);
57 d0c09d70 Andreas Kohlbecker
}
58
59 fee09cdd l.morris
/**
60
* Implementation of hook_ctools_plugin_api().
61
*/
62
function dwca_export_ctools_plugin_api(){
63
	list($module, $api) = func_get_args();
64
	if($module == "strongarm" && $api == "strongarm"){
65
		return array(
66
      "version" => 1
67
		);
68
	}
69
}
70
71 9c7f9ab7 Andreas Kohlbecker
/**
72
 * Form function, called by drupal_get_form()
73
 * in dwca_export_menu().
74
 */
75
function dwca_export_config_form($form, &$form_state) {
76
77 6ab7ce86 Andreas Kohlbecker
	global $base_url;
78
79 dc70e39a n.hoffmann
	$form['dwca_export_info'] = array(
80
		'#markup' => '<p>For general information on the DarwinCore Archive format please refer to  '
81 3ac1e968 Andreas Kohlbecker
		. l('GBIF - Standards and Tools - Darwin Core Archives', 'http://www.gbif.org/informatics/standards-and-tools/publishing-data/data-standards/darwin-core-archives/')
82 6ab7ce86 Andreas Kohlbecker
		.'</p>'
83 9c7f9ab7 Andreas Kohlbecker
	);
84
85 dc70e39a n.hoffmann
	$form['dwca_export_execute'] = array(
86
		'#markup' => '<p>The DarwinCore Archive export is available at '. l('dwca_export', 'dwca_export').'</p>'
87
		//'#type' => 'button',
88
		//'#value' => t('Export Scratchpad to DarwinCore Archive'), 
89
	  //'#weight' => 19,
90
	);
91
	
92
	$form['dwca_export_view_mapping'] = dwca_export_select_view_form();
93
	
94
	
95 ab2258a1 l.morris
96
	$form['#submit'][] = 'dwca_export_config_form_submit';
97 9c7f9ab7 Andreas Kohlbecker
	return system_settings_form($form);
98 ab2258a1 l.morris
99
}
100
101
102
function dwca_export_select_view_form() {
103
104
	$views = array(
105
    		'#type' => 'fieldset',
106 dc70e39a n.hoffmann
    		'#title' => t('View to file mapping'),
107 ab2258a1 l.morris
    		//'#tree' => TRUE,
108
  	);
109
110 fee09cdd l.morris
	foreach(variable_get(FILE_MAP) as $dwca_filename => $view_data){
111 dc70e39a n.hoffmann
		
112 96ddb3af l.morris
		if ($dwca_filename == 'description') {
113
			
114 8de8732c l.morris
			
115
		$views[$dwca_filename] = array (
116
					'#type' => 'fieldset',
117
  					'#title' => t('DESCRIPTIVE DATA TYPES'),
118
				  	'#weight' => 3,
119
				  	'#collapsible' => TRUE,
120
				  	'#collapsed' => TRUE,
121 71920c02 l.morris
					//'#prefix' => '<table>',
122
		  			//'#suffix' => '</table>',	
123
				  	'#tree' => TRUE,
124 8de8732c l.morris
			
125
  		);
126 96ddb3af l.morris
			foreach($view_data as $dwca_filename_inner => $view_data_inner){
127 8de8732c l.morris
				
128
				
129 96ddb3af l.morris
				$views[$dwca_filename][$dwca_filename_inner] = array(
130
									  	'#type' => 'textfield',
131
									  	'#title' => t($dwca_filename . '_' . $dwca_filename_inner),
132
									  	'#default_value' => $view_data_inner['view_name'],
133
									  	'#size' => 60,
134
									  	'#description' => t('specify view for ' . $dwca_filename_inner),
135 71920c02 l.morris
									//'#prefix' => '<tr>',
136
								    //'#suffix' => '</tr>',
137 96ddb3af l.morris
			
138
				);
139 71920c02 l.morris
								
140
				//TODO: Change collaped discription form to table, layout using <td> and <tr> e.g. try 3 description types per row
141
				
142 96ddb3af l.morris
			}
143
			
144
		} else {
145
			$views[$dwca_filename] = array(
146
					  	'#type' => 'textfield',
147
					  	'#title' => t($dwca_filename),
148
					  	'#default_value' => $view_data['view_name'],
149
					  	'#size' => 60,
150
					  	'#description' => t('specify view for ' . $dwca_filename),
151
			
152
			);
153
		}
154 dc70e39a n.hoffmann
	}
155 ab2258a1 l.morris
156
	return $views;
157
}
158
159 96ddb3af l.morris
function dwca_export_config_form_submit($form, &$form_state) {
160 ab2258a1 l.morris
161 fee09cdd l.morris
	$variables = $form_state['input'];
162
	$save_variables = '';
163
	$dwca_export_archive_descriptor_file_map = variable_get(FILE_MAP);
164 96ddb3af l.morris
165 fee09cdd l.morris
	foreach ($variables as $key => $value) {
166 96ddb3af l.morris
167 fee09cdd l.morris
		if (array_key_exists($key, $dwca_export_archive_descriptor_file_map)) {
168 96ddb3af l.morris
169 fee09cdd l.morris
			$dwca_export_archive_descriptor_file_map[$key]['view_name'] = $value;
170 96ddb3af l.morris
			//$save_variables .= '<p>' . $key . ' ' . $value . '</p>';
171
		} else {
172
173
			$description_key = 'description';
174
			
175
			if (array_key_exists($description_key, $dwca_export_archive_descriptor_file_map)) {
176
				
177
				//get the inner array containing the different description data types
178
				$description_map = $dwca_export_archive_descriptor_file_map[$description_key];
179 f6086da6 l.morris
180 96ddb3af l.morris
				if (array_key_exists($key, $description_map)) {
181 8e5c42d1 l.morris
					//drupal_set_message(t('The ooKEY is... ') . $key . t('The ooVALUE is... ') . $value);
182 96ddb3af l.morris
					$dwca_export_archive_descriptor_file_map[$description_key][$key]['view_name'] = $value;
183
				}
184
			}
185
		}
186 fee09cdd l.morris
	}
187 96ddb3af l.morris
188 fee09cdd l.morris
	variable_del(FILE_MAP);
189
	variable_set(FILE_MAP, $dwca_export_archive_descriptor_file_map);
190 96ddb3af l.morris
191 49ea01c8 l.morris
	//drupal_set_message(t('The classification view is ') . $save_variables);// . '<pre>' . print_r($form_state,true) . '</pre>');//$save_variables);
192
}
193
194 96ddb3af l.morris
195
196
197 0aad6e04 l.morris
// Reports an error if view name entered by the user does not exist in the database.
198 49ea01c8 l.morris
function dwca_export_config_form_validate($form, &$form_state) {
199 fee09cdd l.morris
	
200 49ea01c8 l.morris
	$variables = $form_state['input'];
201
	$dwca_export_archive_descriptor_file_map = variable_get(FILE_MAP);
202
	$view_names = array();
203 0aad6e04 l.morris
	$missing_view_names = '';
204
	$missing_view = false;
205 49ea01c8 l.morris
	
206
	foreach ($variables as $key => $value) {
207
		
208 96ddb3af l.morris
		//TODO: Check whether the views for the inner array cotaining all the description views exist
209 49ea01c8 l.morris
		if (array_key_exists($key, $dwca_export_archive_descriptor_file_map)) {
210
					
211
			$view = views_get_view($value);
212
			// check whether there is a view named with this value 
213
			if(!$view) {
214 0aad6e04 l.morris
				$view_names[] = $value;
215
				$missing_view_names .= $value . ', ';
216
				$missing_view = true;
217 49ea01c8 l.morris
			}
218
		}
219
	}
220 fee09cdd l.morris
	
221 0aad6e04 l.morris
	if ($missing_view) {
222
		form_set_error('', t('VIEW(S) ' . $missing_view_names . ' NOT FOUND. Please input another view name.'));
223
	}
224
	
225 9c7f9ab7 Andreas Kohlbecker
}
226
227
/**
228
 * menu callback
229
 */
230
function dwca_export_deliver_archive() {
231
232 7fcb8ba6 Andreas Kohlbecker
	$tmp_archive_file_name = dwca_export_create_archive( _dwca_export_archive_descriptor_file_map() );
233 9c7f9ab7 Andreas Kohlbecker
234 7156bdbf n.hoffmann
	if($tmp_archive_file_name && file_valid_uri($tmp_archive_file_name)){
235 04291712 Andreas Kohlbecker
		file_transfer($tmp_archive_file_name, array('Content-Type' => 'application/zip'));
236
	} else {
237 7156bdbf n.hoffmann
		throw new Exception(t('Error creating the archive'));
238 04291712 Andreas Kohlbecker
	}
239 9c7f9ab7 Andreas Kohlbecker
}
240
241 7fcb8ba6 Andreas Kohlbecker
242
/**
243
 * Provides the archive_descriptor_file_map which maps dwca file name to a set of view information.
244
 * The view information contains the fields 'view_name', 'display_id', 'out_file_url'.
245
 * The 'out_file_url' is initailly empty and will be set when this function is called
246
 * with both parameters.
247
 *
248 dc70e39a n.hoffmann
 * @param String $file_name
249
 * @param String $out_file_url
250 7fcb8ba6 Andreas Kohlbecker
 *
251
 * @return the archive_descriptor_file_map
252
 */
253
function _dwca_export_archive_descriptor_file_map($file_name = NULL, $out_file_url = null){
254
	static $file_map;
255
256
	if(!isset($file_map)){
257 fee09cdd l.morris
		$file_map = variable_get(FILE_MAP);
258 7fcb8ba6 Andreas Kohlbecker
	}
259
260
	if($file_name && $out_file_url){
261 96ddb3af l.morris
		
262 f6086da6 l.morris
		if (in_array($file_name, dwca_export_view_names_array())) {
263 8e5c42d1 l.morris
			
264
			$file_map[$file_name]['out_file_url'] = $out_file_url;
265
			
266 96ddb3af l.morris
		} else {
267 3615aa8e l.morris
		
268 8e5c42d1 l.morris
			$file_map['description'][$file_name]['out_file_url'] = $out_file_url;
269 96ddb3af l.morris
		}
270 7fcb8ba6 Andreas Kohlbecker
	}
271
272
	return $file_map;
273
}
274
275 ab2258a1 l.morris
276 9c7f9ab7 Andreas Kohlbecker
/**
277
 * Walks all view export paths defined in the $views_map.
278
 * Each file is downloaded to the tmp folder and a zip file
279
 * is bundeled of the resulting csv files plus the meta file.
280
 *
281 7fcb8ba6 Andreas Kohlbecker
 * @param $views_map - maps a view paths to dwca filenames
282 9c7f9ab7 Andreas Kohlbecker
 *
283 04291712 Andreas Kohlbecker
 * @return the path in the filesystem to the final archive,
284
 * or FALSE in case of an error.
285 9c7f9ab7 Andreas Kohlbecker
 */
286
function dwca_export_create_archive($views_map) {
287 96ddb3af l.morris
	
288 7fcb8ba6 Andreas Kohlbecker
	// all data is exported to temporary://dwca_export_*
289 dc70e39a n.hoffmann
	// now we can start bundling the actual archive
290 7fcb8ba6 Andreas Kohlbecker
	$tmp_archive_file_name = drupal_tempnam("temporary://", "dwca_export_archive_");
291 96ddb3af l.morris
	
292 7156bdbf n.hoffmann
	// Unfortunately we cannot use drupals ArchiverZip because there ís
293
	// no way to pass in ZipArchive::CREATE to the constructor to create the archive
294
	// TODO test if zip functionality is available (i.e. if(function_exists('zip_open'))
295
	// but I don't know where the proper location for such a check would be
296
	$zip = new ZipArchive();
297
	// it is safe to use drupal_realpath as the tmp file will be certainly local
298
	// and php's ZipArchive does not handle stream URIs
299
	$result = $zip->open(drupal_realpath($tmp_archive_file_name), ZipArchive::CREATE);
300 96ddb3af l.morris
	
301 7156bdbf n.hoffmann
	// there might be a better way to get at this information
302 e3d8e63e n.hoffmann
	$module_static_dir_absolute_path = realpath(drupal_get_path('module', 'dwca_export')) . STATIC_DIR;
303 96ddb3af l.morris
	
304 7156bdbf n.hoffmann
	if ($result !== TRUE) {
305
		throw new Exception(t('Could not create zip_archive %tmp_archive_file_name', array('%tmp_archive_file_name' => $tmp_archive_file_name)));
306 7fcb8ba6 Andreas Kohlbecker
	}
307 96ddb3af l.morris
	
308 95cfb699 n.hoffmann
	
309
	// add metadata
310 e3d8e63e n.hoffmann
	$zip->addFile($module_static_dir_absolute_path.METADATA_FILE_NAME, ARCHIVE_ROOT_DIR.METADATA_FILE_NAME);
311 96ddb3af l.morris
312
	global $base_url;
313
314
	// execute all views to export the data into
315
	// temporary csv files (temporary://dwca_export_*). the resulting filenames
316
	// will be stored in _dwca_export_archive_descriptor_file_map()
317
	foreach($views_map as $filename=>$view_data){
318
	
319
		//lorna
320
		if ($filename == 'description') {
321
			
322
			//lorna: this foreach iterates through all the description types in the inner array
323
			foreach($view_data as $filename_inner => $view_data_inner){
324
				$view = views_get_view($view_data_inner['view_name']);
325
					
326
				$options = array (
327 3615aa8e l.morris
					'output_file' => $filename_inner
328
				);
329 96ddb3af l.morris
					
330
				_dwca_export_views_data_export_override_batch($view, $view_data_inner['display_id'], $options);
331 53643c8a l.morris
332
				if ($view) {
333
					$view->execute_display($view_data_inner['display_id']);
334
				}else{
335
					throw new Exception(t('A view with the name %view does not exist', array('%view' => $view_data_inner['view_name'])));
336
				}
337 96ddb3af l.morris
			}
338
			
339
		}
340
		else {
341
			$view = views_get_view($view_data['view_name']);
342
			$options = array (
343
					    'output_file' => $filename
344
			);
345
			_dwca_export_views_data_export_override_batch($view, $view_data['display_id'], $options);
346 53643c8a l.morris
				
347
			if ($view) {
348
				$view->execute_display($view_data['display_id']);
349
			} else{
350
				throw new Exception(t('A view with the name %view does not exist', array('%view' => $view_data['view_name'])));
351
			}
352 96ddb3af l.morris
		}
353
		//end lorna
354 53643c8a l.morris
355 96ddb3af l.morris
	}
356
357 95cfb699 n.hoffmann
	// add the csv data files
358 7fcb8ba6 Andreas Kohlbecker
	foreach(_dwca_export_archive_descriptor_file_map() as $dwca_filename=>$view_data){
359
360 96ddb3af l.morris
		if ($dwca_filename == 'description') {
361
			
362 1c0bd967 l.morris
			_dwca_export_concatenate_description_files($view_data, $zip);
363 96ddb3af l.morris
			
364
		} else {
365
		
366
			$view_temp_file = $view_data['out_file_url'];
367
			_dwca_export_add_files_to_zip($view_temp_file, $dwca_filename, $zip);
368 7156bdbf n.hoffmann
		}
369 96ddb3af l.morris
		
370 7fcb8ba6 Andreas Kohlbecker
	}
371
372
	$zip->close();
373
374
	return $tmp_archive_file_name;
375 7156bdbf n.hoffmann
}
376
377 1c0bd967 l.morris
/**
378
 * 
379 3615aa8e l.morris
 * Combines multiple Description Views for different description types into a single text file
380 1c0bd967 l.morris
 * @param $view_data The inner array containing the view data for the different description types
381
 * @param $zip The zip file for the files making up the DwC-A.
382
 */
383
function _dwca_export_concatenate_description_files($view_data, $zip){
384
	
385
	$desc_file_name = drupal_tempnam("temporary://", "description.tmp");
386 f6086da6 l.morris
	$desc_file = fopen(drupal_realpath($desc_file_name), "w");	
387 8e5c42d1 l.morris
	
388 1c0bd967 l.morris
	foreach($view_data as $type=>$view_data_inner){
389
390
		$view_temp_file = $view_data_inner['out_file_url'];
391
392 8e5c42d1 l.morris
		$descTypeFile = fopen($view_temp_file, "r");
393 1c0bd967 l.morris
394 8e5c42d1 l.morris
		while(!feof($descTypeFile)){
395
			$lineOfText = fgets($descTypeFile, 4096);
396 1c0bd967 l.morris
397
			$items = explode(',', $lineOfText);
398 40d82d25 l.morris
			
399 8e5c42d1 l.morris
			//don't include empty descriptions or lines at the end of the view which start with the field name id
400 40d82d25 l.morris
			//some lines just contain a single " if there is a carriage return within the description text so remove these too
401 71920c02 l.morris
			
402
			if (isset($items[0]) && isset($items[2])) {
403 40d82d25 l.morris
				
404 71920c02 l.morris
				if ($items[0]!=="\"id\""  && trim($items[2])!=="\"\"") {
405 8e5c42d1 l.morris
				
406 71920c02 l.morris
					// fix conflict with files that have an EOL that differs from the server EOL
407
					$lineOfText = rtrim($lineOfText, "\r\n") . PHP_EOL;
408
					fwrite($desc_file, $lineOfText);
409 40d82d25 l.morris
				
410 71920c02 l.morris
				}	
411 8e5c42d1 l.morris
				
412 1c0bd967 l.morris
			} else {
413 8e5c42d1 l.morris
				fgets($descTypeFile, 4096);
414 1c0bd967 l.morris
			}
415
416
		}
417
418 8e5c42d1 l.morris
		fclose($descTypeFile);
419 1c0bd967 l.morris
	}
420
	fclose($desc_file);
421
422
	_dwca_export_add_files_to_zip($desc_file_name, 'description', $zip);
423
}
424
425 96ddb3af l.morris
function _dwca_export_add_files_to_zip($view_temp_file = NULL, $dwca_filename, $zip){
426
	
427
	if($view_temp_file){
428 53643c8a l.morris
		$zip->addFile(drupal_realpath($view_temp_file), ARCHIVE_ROOT_DIR.$dwca_filename . FILE_EXTENSION);
429 96ddb3af l.morris
	}else{
430
		throw new Exception(t('Cannot create %file', array('%file' => $dwca_filename)));
431
	}
432
}
433
434 7156bdbf n.hoffmann
/**
435 7fcb8ba6 Andreas Kohlbecker
 * Helper function that indicates that we want to
436
 * override the batch that the views_data_export view creates
437
 * on it's initial time through.
438 7156bdbf n.hoffmann
 *
439 7fcb8ba6 Andreas Kohlbecker
 * Also provides a place to stash options that need to stay around
440
 * until the end of the batch
441
 *
442
 * adapted fom views_data_export.drush.inc
443 7156bdbf n.hoffmann
 */
444 7fcb8ba6 Andreas Kohlbecker
function _dwca_export_views_data_export_override_batch($view = NULL, $display = NULL, $options = TRUE) {
445 96ddb3af l.morris
	
446 7fcb8ba6 Andreas Kohlbecker
	static $_views;
447
	if (isset($view)) {
448 96ddb3af l.morris
		
449 7fcb8ba6 Andreas Kohlbecker
		$_views[$view->name][$display] = $options;
450
	}
451
	return $_views;
452 9c7f9ab7 Andreas Kohlbecker
}
453
454 7fcb8ba6 Andreas Kohlbecker
455 9c7f9ab7 Andreas Kohlbecker
/**
456 7fcb8ba6 Andreas Kohlbecker
 * Implementation of hook_views_data_export_batch_alter()
457
 *
458
 * adapted fom views_data_export.drush.inc
459 9c7f9ab7 Andreas Kohlbecker
 *
460 7fcb8ba6 Andreas Kohlbecker
 *  @see batch_process() in form.inc
461 9c7f9ab7 Andreas Kohlbecker
 */
462 7fcb8ba6 Andreas Kohlbecker
function dwca_export_views_data_export_batch_alter(&$batch, &$final_destination, &$querystring) {
463 9c7f9ab7 Andreas Kohlbecker
464 7fcb8ba6 Andreas Kohlbecker
	$view_name = $batch['view_name'];
465
	$display_id = $batch['display_id'];
466
467
	$ok_to_override = _dwca_export_views_data_export_override_batch();
468
469
	// Make sure we do nothing if we are called not following the execution of
470
	// our drush command. This could happen if the file with this function in it
471
	// is included during the normal execution of the view
472
	if (!$ok_to_override[$view_name][$display_id]) {
473
		return;
474
	}
475
476
	$options = $ok_to_override[$view_name][$display_id];
477
478
	// We actually never return from the drupal_alter, but
479
	// use drush's batch system to run the same batch
480
481
	// Add a final callback
482
	$batch['operations'][] = array(
483
	    '_dwca_export_views_data_export_batch_finished', array($batch['eid'], $options['output_file']),
484 9c7f9ab7 Andreas Kohlbecker
	);
485 7fcb8ba6 Andreas Kohlbecker
486
	$batch['progressive'] = FALSE;
487
}
488
489
/**
490
* Implementation of hook_views_data_export_batch_alter()
491
*
492
* @see batch_process() in form.inc
493
*/
494
function dwca_export_batch_alter(&$batch, &$final_destination, &$querystring) {
495 96ddb3af l.morris
	
496 7fcb8ba6 Andreas Kohlbecker
	if($batch['source_url'] == 'dwca_export'){
497
		$batch['progressive'] = FALSE;
498
	}
499
}
500
501
502
503
/**
504
* Get's called at the end of the drush batch process that generated our export
505
*
506
* adapted fom views_data_export.drush.inc
507
*/
508
function _dwca_export_views_data_export_batch_finished($eid, $output_file, &$context) {
509
	// Fetch export info
510
	$export = views_data_export_get($eid);
511
512
	// Perform cleanup
513
	$view = views_data_export_view_retrieve($eid);
514
	$view->set_display($export->view_display_id);
515
	$view->display_handler->batched_execution_state = $export;
516
	$view->display_handler->remove_index();
517
518
	// Get path to temp file
519
	$temp_file = $view->display_handler->outputfile_path();
520
521
	_dwca_export_archive_descriptor_file_map($output_file, $temp_file);
522
523 5264445c l.morris
}
524
525
function dwca_export_permission() {
526
	return array(
527
    'administer dwca-export' => array(
528
      'title' => t('Access dwca-export'),
529
      'description' => t('Allows user to access DwC-A export configuration page and execute export of the DwC-A data.'),
530
	));
531 9c7f9ab7 Andreas Kohlbecker
}