Index: trunk/grails-app/controllers/PersonController.groovy
===================================================================
--- trunk/grails-app/controllers/PersonController.groovy	(revision 439)
+++ trunk/grails-app/controllers/PersonController.groovy	(revision 440)
@@ -1,9 +1,11 @@
 import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
 
 @Secured(['ROLE_Manager','ROLE_AppAdmin'])
 class PersonController extends BaseAppAdminController {
 
+    def filterService
+    def personCsvService
     def authenticateService
-    def filterService
 
     // the delete, save and update actions only accept POST requests
@@ -12,4 +14,39 @@
     def index = {
         redirect action: list, params: params
+    }
+
+    /**
+    * Disaply the import view.
+    */
+    def importPersons = {
+    }
+
+    /**
+    * Handle the import save.
+    */
+    def importPersonsSave = {
+        def result = personCsvService.importPersons(request)
+
+        if(!result.error) {
+            response.contentType = ConfigurationHolder.config.grails.mime.types["text"]
+            response.setHeader("Content-disposition", "attachment; filename=LoginNamesAndPasswords.txt")
+            render result.loginNamesAndPasswords
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: importPersons)
+    }
+
+    /**
+    * Export a csv template.
+    * NOTE: IE has a 'validating' bug in dev mode that causes the export to take a long time!
+    * This does not appear to be a problem once deployed to Tomcat.
+    */
+    def exportPersonsTemplate = {
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=personsTemplate.csv")
+        def s = personCsvService.buildPersonsTemplate()
+        render s
     }
 
