source: main/waeup.kofa/trunk/src/waeup/kofa/doctests/batchprocessing_browser.txt @ 15709

Last change on this file since 15709 was 15416, checked in by Henrik Bettermann, 5 years ago

Backup deleted graduated student data somewhere else to ease graduated student data migration.

File size: 20.6 KB
Line 
1Batch Processing via Browser
2****************************
3
4Preliminaries:
5
6We define a function that looks up a form with several submit buttons
7for the one with a given value (this functionality is missing in
8zope.testbrowser):
9
10    >>> def lookup_submit_value(name, value, browser):
11    ...   """Find a button with a certain value."""
12    ...   for num in range(0, 100):
13    ...     try:
14    ...       button = browser.getControl(name=name, index=num)
15    ...       if button.value.endswith(value):
16    ...         return button
17    ...     except IndexError:
18    ...       break
19    ...   return None
20
21Create a site:
22
23    >>> from waeup.kofa.app import University
24    >>> getRootFolder()['app'] = University()
25    >>> from zope.component.hooks import setSite
26    >>> setSite(getRootFolder()['app'])
27
28Create a datacenter storage path:
29
30    >>> import os
31    >>> import tempfile
32    >>> dc_path = tempfile.mkdtemp()
33
34Log in:
35
36    >>> from zope.testbrowser.testing import Browser
37    >>> browser = Browser()
38    >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
39    >>> browser.handleErrors = False
40
41Set datacenter path and deselect moving old data:
42
43    >>> browser.open('http://localhost/app')
44    >>> browser.getLink('Data Center').click()
45    >>> browser.getLink('Edit settings').click()
46    >>> browser.getControl(name='newpath').value = dc_path
47    >>> browser.getControl(name='move').value = False
48    >>> browser.getControl(name='save').click()
49
50Set non-usable datacenter path:
51
52    >>> browser.getLink('Edit settings').click()
53    >>> browser.getControl(name='newpath').value = '/'
54    >>> browser.getControl(name='save').click()
55    >>> 'Given storage path cannot be used.' in browser.contents
56    True
57    >>> browser.getControl('Back to Data Center').click()
58
59
60Batch Processing Faculties
61==========================
62
63Go to datacenter page:
64
65    >>> browser.open('http://localhost/app/datacenter')
66
67Prepare a CSV file for faculties (extended ascii values are accepted):
68
69    >>> open('faculties.csv', 'wb').write(
70    ... """code,title,title_prefix
71    ... FAC1,Faculty 1,faculty
72    ... FAC2,Faculty 2,institute
73    ... FAC3,Fäcülty 3,school
74    ... """)
75
76Upload the file:
77
78    >>> import cStringIO
79    >>> browser.getLink('Upload data').click()
80    >>> filecontents = cStringIO.StringIO(
81    ...   open('faculties.csv', 'rb').read())
82    >>> filewidget = browser.getControl(name='uploadfile:file')
83    >>> filewidget.add_file(filecontents, 'text/plain', 'faculties.csv')
84    >>> browser.getControl(name='SUBMIT').click()
85
86Step 1: start batch processing:
87
88    >>> browser.getLink('Process data').click()
89    >>> browser.getLink('Switch maintenance mode').click()
90    >>> button = lookup_submit_value(
91    ...   'select', 'faculties_zope.mgr.csv', browser)
92    >>> button.click()
93
94Step 2: select a processor and mode:
95
96    >>> importerselect = browser.getControl(name='importer')
97    >>> importerselect.displayOptions
98    ['AccessCodeBatch Processor',
99    'AccessCode Processor',
100    'ApplicantOnlinePayment Processor',
101    'Applicant Processor',
102    'ApplicantsContainer Processor',
103    'Bed Processor (update only)',
104    'CertificateCourse Processor',
105    'Certificate Processor',
106    'Course Processor',
107    'CourseTicket Processor',
108    'Department Processor',
109    'Faculty Processor',
110    'Hostel Processor',
111    'Public HTML Document Processor',
112    'StudentOnlinePayment Processor',
113    'Public PDF Document Processor',
114    'Public REST Document Processor',
115    'Student Processor',
116    'StudentStudyCourse Processor (update only)',
117    'StudentStudyLevel Processor',
118    'User Processor',
119    'Verdict Processor (special processor, update only)']
120
121    >>> importerselect.getControl('Faculty Processor').selected = True
122
123    >>> modeselect = browser.getControl(name='mode')
124    >>> modeselect.options
125    ['create', 'update', 'remove']
126
127    >>> modeselect.getControl(value='create').selected = True
128    >>> browser.getControl('Proceed to step 3').click()
129
130Step 3: Fix headerlines
131
132We get informed that there are no problems with the current header:
133
134    >>> print browser.contents
135    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
136    ...
137    Header fields OK
138    ...
139
140The submit button is enabled:
141
142    >>> browser.getControl('Perform import').disabled
143    False
144
145    >>> browser.getControl('Perform import').click()
146
147Step 4: See import results
148
149The import was successful:
150
151    >>> print browser.contents
152    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
153    ...Successfully processed 3 rows...
154    ...Batch processing finished...
155    ...File:...faculties_zope.mgr.csv...
156
157We can grep the entries generated in logfile:
158
159    >>> browser.open('http://localhost/app/datacenter/logs')
160    >>> browser.getControl('Show', index=0).click()
161    >>> print browser.contents
162    <!DOCTYPE ...
163    ...<h1 class="kofa-content-label">Logfile datacenter.log</h1>...
164
165    >>> browser.getControl(name='query').value = "zope.mgr"
166    >>> browser.getControl('Search').click()
167    >>> 'zope.mgr - processed' in browser.contents
168    True
169
170
171Batch Processing Departments
172============================
173
174    >>> browser.open('http://localhost/app/datacenter')
175
176Prepare a CSV file for departments:
177
178    >>> open('departments.csv', 'wb').write(
179    ... """code,faculty_code,title,title_prefix
180    ... DEP1,FAC1,Department 1,department
181    ... DEP2,FAC2,Department 2,centre
182    ... """)
183
184Upload the file:
185
186    >>> import cStringIO
187    >>> browser.getLink('Upload data').click()
188    >>> filecontents = cStringIO.StringIO(
189    ...   open('departments.csv', 'rb').read())
190    >>> filewidget = browser.getControl(name='uploadfile:file')
191    >>> filewidget.add_file(filecontents, 'text/plain', 'departments.csv')
192    >>> browser.getControl(name='SUBMIT').click()
193
194Step 1: start batch processing:
195
196    >>> browser.getLink('Process data').click()
197    >>> browser.getLink('Switch maintenance mode').click()
198    >>> button = lookup_submit_value(
199    ...   'select', 'departments_zope.mgr.csv', browser)
200    >>> button.click()
201
202Step 2: select a processor and mode:
203
204    >>> importerselect = browser.getControl(name='importer')
205    >>> importerselect.getControl('Department Processor').selected = True
206    >>> modeselect = browser.getControl(name='mode')
207    >>> modeselect.getControl(value='create').selected = True
208    >>> browser.getControl('Proceed to step 3').click()
209
210Step 3: Fix headerlines
211
212We get informed that there are no problems with the current header:
213
214    >>> print browser.contents
215    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
216    ...
217    Header fields OK
218    ...
219
220The submit button is enabled:
221
222    >>> browser.getControl('Perform import').disabled
223    False
224
225    >>> browser.getControl('Perform import').click()
226
227Step 4: See import results
228
229The import was successful:
230
231    >>> print browser.contents
232    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
233    ...Successfully processed 2 rows...
234    ...Batch processing finished...
235    ...File:...departments_zope.mgr.csv...
236
237Batch Processing Courses
238========================
239
240    >>> browser.open('http://localhost/app/datacenter')
241
242Prepare a CSV file for courses:
243
244    >>> open('courses.csv', 'wb').write(
245    ... """code,faculty_code,department_code,title,level,passmark,credits,semester
246    ... CRS1,FAC1,DEP1,Course 1,100,40,2,1
247    ... CRS2,FAC1,DEP1,Course 2,100,40,2,2
248    ... """)
249
250Upload the file:
251
252    >>> import cStringIO
253    >>> browser.getLink('Upload data').click()
254    >>> filecontents = cStringIO.StringIO(
255    ...   open('courses.csv', 'rb').read())
256    >>> filewidget = browser.getControl(name='uploadfile:file')
257    >>> filewidget.add_file(filecontents, 'text/plain', 'courses.csv')
258    >>> browser.getControl(name='SUBMIT').click()
259
260Step 1: start batch processing:
261
262    >>> browser.getLink('Process data').click()
263    >>> browser.getLink('Switch maintenance mode').click()
264    >>> button = lookup_submit_value(
265    ...   'select', 'courses_zope.mgr.csv', browser)
266    >>> button.click()
267
268Step 2: select a processor and mode:
269
270    >>> importerselect = browser.getControl(name='importer')
271    >>> importerselect.getControl('Course Processor', index=1).selected = True
272    >>> modeselect = browser.getControl(name='mode')
273    >>> modeselect.getControl(value='create').selected = True
274    >>> browser.getControl('Proceed to step 3').click()
275
276Step 3: Fix headerlines
277
278We get informed that there are no problems with the current header:
279
280    >>> print browser.contents
281    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
282    ...
283    Header fields OK
284    ...
285
286The submit button is enabled:
287
288    >>> browser.getControl('Perform import').disabled
289    False
290
291    >>> browser.getControl('Perform import').click()
292
293Step 4: See import results
294
295The import was successful:
296
297    >>> print browser.contents
298    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
299    ...Successfully processed 2 rows...
300    ...Batch processing finished...
301    ...File:...courses_zope.mgr.csv...
302
303Batch Processing Certificates
304=============================
305
306    >>> browser.open('http://localhost/app/datacenter')
307
308Prepare a CSV file for certificates:
309
310    >>> open('certificates.csv', 'wb').write(
311    ... """code,faculty_code,department_code,title,study_mode,start_level,end_level,application_category
312    ... CERT1,FAC1,DEP1,Certificate 1,pg_ft,999,999,basic
313    ... CERT2,FAC1,DEP1,Certificate 2,ug_ft,200,300,cest
314    ... """)
315
316Upload the file:
317
318    >>> import cStringIO
319    >>> browser.getLink('Upload data').click()
320    >>> filecontents = cStringIO.StringIO(
321    ...   open('certificates.csv', 'rb').read())
322    >>> filewidget = browser.getControl(name='uploadfile:file')
323    >>> filewidget.add_file(filecontents, 'text/plain', 'certificates.csv')
324    >>> browser.getControl(name='SUBMIT').click()
325
326Step 1: start batch processing:
327
328    >>> browser.getLink('Process data').click()
329    >>> browser.getLink('Switch maintenance mode').click()
330    >>> button = lookup_submit_value(
331    ...   'select', 'certificates_zope.mgr.csv', browser)
332    >>> button.click()
333
334
335Step 2: select a processor and mode:
336
337    >>> importerselect = browser.getControl(name='importer')
338    >>> importerselect.getControl('Certificate Processor').selected = True
339    >>> modeselect = browser.getControl(name='mode')
340    >>> modeselect.getControl(value='create').selected = True
341    >>> browser.getControl('Proceed to step 3').click()
342
343Step 3: Fix headerlines
344
345We get informed that there are no problems with the current header:
346
347    >>> print browser.contents
348    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
349    ...
350    Header fields OK
351    ...
352
353The submit button is enabled:
354
355    >>> browser.getControl('Perform import').disabled
356    False
357
358    >>> browser.getControl('Perform import').click()
359
360Step 4: See import results
361
362The import was successful:
363
364    >>> print browser.contents
365    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
366    ...Successfully processed 2 rows...
367    ...Batch processing finished...
368    ...File:...certificates_zope.mgr.csv...
369
370Batch Processing Certificate Courses
371====================================
372
373    >>> browser.open('http://localhost/app/datacenter')
374
375Prepare a CSV file for certificate courses:
376
377    >>> open('mycertcourses.csv', 'wb').write(
378    ... """course,faculty_code,department_code,certificate_code,level,mandatory
379    ... CRS1,FAC1,DEP1,CERT1,100,True
380    ... CRS2,FAC1,DEP1,CERT1,100,True
381    ... """)
382
383Upload the file:
384
385    >>> import cStringIO
386    >>> browser.getLink('Upload data').click()
387    >>> filecontents = cStringIO.StringIO(
388    ...   open('mycertcourses.csv', 'rb').read())
389    >>> filewidget = browser.getControl(name='uploadfile:file')
390    >>> filewidget.add_file(filecontents, 'text/plain', 'mycertcourses.csv')
391    >>> browser.getControl(name='SUBMIT').click()
392
393Step 1: start batch processing:
394
395    >>> browser.getLink('Process data').click()
396    >>> browser.getLink('Switch maintenance mode').click()
397    >>> button = lookup_submit_value(
398    ...   'select', 'mycertcourses_zope.mgr.csv', browser)
399    >>> button.click()
400
401Step 2: select a processor and mode:
402
403    >>> importerselect = browser.getControl(name='importer')
404    >>> importerselect.getControl('CertificateCourse Processor').selected = True
405    >>> modeselect = browser.getControl(name='mode')
406    >>> modeselect.getControl(value='create').selected = True
407    >>> browser.getControl('Proceed to step 3').click()
408
409Step 3: Fix headerlines
410
411We get informed that there are no problems with the current header:
412
413    >>> print browser.contents
414    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
415    ...
416    Header fields OK
417    ...
418
419The submit button is enabled:
420
421    >>> browser.getControl('Perform import').disabled
422    False
423
424    >>> browser.getControl('Perform import').click()
425
426Step 4: See import results
427
428The import was successful:
429
430    >>> print browser.contents
431    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
432    ...Successfully processed 2 rows...
433    ...Batch processing finished...
434    ...File:...mycertcourses_zope.mgr.csv...
435
436Batch Processing Users
437======================
438
439    >>> browser.open('http://localhost/app/datacenter')
440
441Prepare a CSV file for users:
442
443    >>> open('users.csv', 'wb').write(
444    ... """name,title,public_name,email,phone,roles
445    ... uli,Uli Fouquet,Chief Developer,uli@abc.de,+49-234-567,[]
446    ... henrik,Henrik Bettermann,Admin,henrik@abc.de,+49-234-567,"['waeup.PortalManager', 'waeup.ImportManager']"
447    ... anne,Anne Palina,,anne@abc.de,+49-234-567,"['waeup.Nonsense']"
448    ... """)
449
450Upload the file:
451
452    >>> import cStringIO
453    >>> browser.getLink('Upload data').click()
454    >>> filecontents = cStringIO.StringIO(
455    ...   open('users.csv', 'rb').read())
456    >>> filewidget = browser.getControl(name='uploadfile:file')
457    >>> filewidget.add_file(filecontents, 'text/plain', 'users.csv')
458    >>> browser.getControl(name='SUBMIT').click()
459
460Step 1: start batch processing:
461
462    >>> browser.getLink('Process data').click()
463    >>> browser.getLink('Switch maintenance mode').click()
464    >>> button = lookup_submit_value(
465    ...   'select', 'users_zope.mgr.csv', browser)
466    >>> button.click()
467
468Step 2: select a processor and mode:
469
470    >>> importerselect = browser.getControl(name='importer')
471    >>> importerselect.getControl('User Processor').selected = True
472    >>> modeselect = browser.getControl(name='mode')
473    >>> modeselect.getControl(value='create').selected = True
474    >>> browser.getControl('Proceed to step 3').click()
475
476Step 3: Fix headerlines
477
478We get informed that there are no problems with the current header:
479
480    >>> print browser.contents
481    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
482    ...
483    Header fields OK
484    ...
485
486The submit button is enabled:
487
488    >>> browser.getControl('Perform import').disabled
489    False
490
491    >>> browser.getControl('Perform import').click()
492
493Step 4: See import results
494
495The import was successful:
496
497    >>> print browser.contents
498    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
499    ...Successfully processed 2 rows...
500    ...Batch processing finished...
501    ...File:...users_zope.mgr.csv...
502
503User henrik has got the global roles:
504
505   >>> henrik = getRootFolder()['app']['users']['henrik']
506   >>> henrik.roles
507   ['waeup.PortalManager', 'waeup.AcademicsOfficer', 'waeup.ImportManager']
508
509Pending Files
510=============
511
512When an error occurs during an import, two files are generated: a CSV
513file with finished files and a CSV file with pending data. Both are
514stored in the appropriate subdirectories in datacenter. We try to
515create faculties, from which one already exists.
516
517Go to datacenter page:
518
519    >>> browser.open('http://localhost/app/datacenter')
520
521Prepare a CSV file for faculties:
522
523    >>> open('newfaculties.csv', 'wb').write(
524    ... """code,title,title_prefix
525    ... FAC1,Faculty 1,faculty
526    ... FAC4,Faculty 4,school
527    ... FAC 5,Faculty 5,faculty
528    ... """)
529
530Upload the file:
531
532    >>> import cStringIO
533    >>> browser.getLink('Upload data').click()
534    >>> filecontents = cStringIO.StringIO(
535    ...   open('newfaculties.csv', 'rb').read())
536    >>> filewidget = browser.getControl(name='uploadfile:file')
537    >>> filewidget.add_file(filecontents, 'text/plain', 'newfaculties.csv')
538    >>> browser.getControl(name='SUBMIT').click()
539
540Since we now have a user with waeup.ImportManager role, an email has been sent:
541    >>> print browser.contents
542    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
543    ...
544    ...All import managers have been notified by email...
545    ...
546
547Step 1: start batch processing:
548
549    >>> browser.getLink('Process data').click()
550    >>> browser.getLink('Switch maintenance mode').click()
551    >>> button = lookup_submit_value(
552    ...   'select', 'newfaculties_zope.mgr.csv', browser)
553    >>> button.click()
554
555Step 2: select a processor and mode:
556
557    >>> importerselect = browser.getControl(name='importer')
558    >>> importerselect.getControl('Faculty Processor').selected = True
559    >>> modeselect = browser.getControl(name='mode')
560    >>> modeselect.getControl(value='create').selected = True
561    >>> browser.getControl('Proceed to step 3').click()
562
563Step 3: Fix headerlines
564
565As there should be no problem with the headers, we can immediately
566perfom the import:
567
568    >>> browser.getControl('Perform import').click()
569
570Two lines could not be imported:
571
572    >>> print browser.contents
573    <!DOCTYPE html PUBLIC...
574    ...
575    ...Processing of 2 rows failed...
576    ...Successfully processed 1 rows...
577    ...
578
579Now there are two files as a result in datacenter storage's root and
580``finished`` dirs:
581
582    >>> pending_file = dc_path + '/newfaculties_zope.mgr.create.pending.csv'
583    >>> print open(pending_file).read()
584    title_prefix,code,title,--ERRORS--
585    faculty,FAC1,Faculty 1,This object already exists.
586    faculty,FAC 5,Faculty 5,code: Invalid input
587
588    >>> finished_file = dc_path + '/finished/newfaculties_zope.mgr.create.finished.csv'
589    >>> print open(finished_file).read()
590    title_prefix,code,title
591    school,FAC4,Faculty 4
592
593The finished-file contains the dataset we could import, while the
594pending file contains the dataset that failed, appended by an error
595message.
596
597
598Fixing the Pending File
599-----------------------
600
601We 'edit' the pending file (setting code to ``FAC5`` and title
602appropriately, and removing the --ERROR-- column) and finish the
603import this way:
604
605    >>> open(dc_path + '/newfaculties_zope.mgr.create.pending.csv', 'wb').write(
606    ... """title_prefix,--IGNORE--,code,title
607    ... faculty,,FAC5,Faculty 5
608    ... """)
609
610Step 1: start batch processing:
611
612    >>> browser.open('http://localhost/app/datacenter')
613    >>> browser.getLink('Process data').click()
614    >>> browser.getLink('Switch maintenance mode').click()
615    >>> button = lookup_submit_value(
616    ...   'select', 'newfaculties_zope.mgr.create.pending.csv', browser)
617    >>> button.click()
618
619Step 2: select a processor and mode:
620
621    >>> importerselect = browser.getControl(name='importer')
622    >>> importerselect.getControl('Faculty Processor').selected = True
623    >>> modeselect = browser.getControl(name='mode')
624    >>> modeselect.getControl(value='create').selected = True
625    >>> browser.getControl('Proceed to step 3').click()
626
627Step 3/4: Fix headerlines and import:
628
629As there should be no problem with the headers, we can immediately
630perfom the import:
631
632    >>> browser.getControl('Perform import').click()
633
634This time everything should work:
635
636    >>> print browser.contents
637    <!DOCTYPE html PUBLIC...
638    ...
639    ...Successfully processed 1 rows...
640    ...
641
642Oh no, we forgot Anne Palina. Her user record was not imported because
643she has a non-existent role:
644
645    >>> sorted(os.listdir(dc_path))
646    ['deleted', 'finished', 'graduated', 'logs', 'unfinished', 'users_zope.mgr.create.pending.csv']
647
648    >>> os.listdir(dc_path + '/unfinished')
649    ['users_zope.mgr.csv']
650
651    >>> pending_file = dc_path + '/users_zope.mgr.create.pending.csv'
652    >>> print open(pending_file).read()
653    name,roles,title,public_name,phone,email,--ERRORS--
654    anne,['waeup.Nonsense'],Anne Palina,<IGNORE>,+49-234-567,anne@abc.de,roles: invalid role
655
656There are many finished-files:
657
658    >>> sorted(os.listdir(dc_path + '/finished'))
659    ['certificates_zope.mgr.create.finished.csv', ...,
660    'users_zope.mgr.create.finished.csv']
661
662Processed (finished) Files
663==========================
664
665    >>> browser.open('http://localhost/app/datacenter/processed')
666    >>> 'download?filename=finished/certificates_zope.mgr.create.finished.csv' in browser.contents
667    True
668
669Log Files
670=========
671
672    >>> browser.open('http://localhost/app/datacenter/logs')
673    >>> 'datacenter.log' in browser.contents
674    True
675    >>> browser.getControl('Show', index=0).click()
676    >>> browser.getControl('Back', index=0).click()
677    >>> browser.getControl('Back to Data Center').click()
678    >>> 'Storage path:' in browser.contents
679    True
680
681
682Clean up:
683
684    >>> import shutil
685    >>> shutil.rmtree(dc_path)
Note: See TracBrowser for help on using the repository browser.