-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathas_xtf_GUI.py
2260 lines (2111 loc) · 134 KB
/
as_xtf_GUI.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
PySimpleGUI_License = "eky4JTMIaWWdNnlibQnMNjlgVlHTlzwtZkSGIN6oICkyRQp8cq3CRDyealWOJw1fdFG5luvDbsieI3sDI1kJxnp1YZ2SVku9cu2qVHJbRuC6IP6NMnT4clx9NSTMIe3QOBToUY3FMbygwqi2ToGmlnjWZMWk5VzbZxUhRYlScJGCxlvjeNWR1zllbvnuRiWzZeXrJWzuatWh9huUI2j4oDilN9Sj4lwFIWivwuiTTMm2FkthZ6U2ZwpbcRnwNi0KIcj0oQikUV3cBZlFYZ2ulJhUb6CFITsVIHky5ghCbWWVVUMlY7X3NA0tIEj7oOiOQG2o97sobWG7VRjYdYGilJvwb9nZMyioLNCtJoDZbq2o1HwKYfWI595lIIjkoWitVNWN5Vpfd4mOVLyYc32bll03e5SzBYvKZbilBaHiZOWa9Cy2ZM2IlshtI7EDxupTYwn7Jch2cVmxlQl1cqyXIvsEIgkvN51dch3URQvzb5WNVfyyS6ULQLixOmi8IfxMOkDHYW5gNdiWIXs0IRkyRIhAd5G3VVJrc13wNX1IZBWqQeihOkidIWy5M6DzIJ00LzTIAU16LxTyAd5XIpi3wwiWRAGCFe0OZ4UBVV4Yc6GelOygZtXqMBidOuiLIyyvMVDKI51ALNTJAC1lLzTSApzzIyiWwGipRvW01Dh6aLWtxdBJZ4G0Rky9ZCXDNaz8IEjaoliccH2PNIs4ZYGiliniaDX1RchHbME8Ba1EZb2tE8unZAWTRl11IFiPwFiTSQVRBEBBZbGuRvyKZaXjNFzuIYjkoIicMXTXke4ULNj5EjzuNOyZ44yuMpCU4HxyOxTiAuiJfjQB=l=p79452967a1198872f2076207dc26aefbad52cf78b5841720c10a5ef7e5a0d1b03960cf9f69db974ab5806240acf02fbad7f35ff3bb355bfc507a520fbde5267c10df5376c30747edc5a14bb1e33e799539d746a43fd1ac46f3f6e7c9fd449a01b230dfbede9f89b96b3d1a658f2b8cf343252dca9ca07273d91e7b9b02db598ccbdb4eac7c2220c86d795562a395f2c957fb165629d6f3e1970d4caea03d191a05429d90c92cd8ece88ea950eaf04263adb90282984acc83e36ab95f3a5d9351ae6715eb4f5884cd836cc750113b7c0a625c791ecf6b36ae51886f42616275422d23d6c283ec2b0cbcec618274b0917d1f05ea164b08e25d27f290501998747d6ccf51117b2fdca9d5987205c7019a8344fc7db7915dffdd1a4ba6b0b4d3a9f3f1b1b37aa5752cef9924af3eab3e9ad0fe330bd75b11b82902e05ae5e039d90f2b64a3225d829cf9010d792c82a0ebd7d1b8913e20dfcb2dd2c95df4a273bcfc92ef704f93dfa0df21b097107d43520a357e61b9850bbec01f8f05c0c4413918b1e485d37e0fab8a4414c0651c828b3c3724dcd674a54ff87be9e68c4e9f7772fdf8022402ad806069946fa6d8cb1cf573611df19bde83715fe64235cd38a2657bb1fde9b387b810da7c6b186a7cc49480a3dd0c471470f2973d7333f90dd464737bfe63310aae9a6e173ce12a7f6e26a0627e959956904e11bb3baa2032c64b"
import os
import platform
import subprocess
import sys
import webbrowser
import json
import re
import time
from loguru import logger
from pathlib import Path
import PySimpleGUI as sg
from asnake.client import ASnakeClient
from asnake.client.web_client import ASnakeAuthError
import as_export as asx
import cleanup as clean
import xtf_upload as xup
import defaults_setup as dsetup
import requests
import threading
import gc
EAD_EXPORT_THREAD = '-EAD_THREAD-'
EXPORT_PROGRESS_THREAD = '-EXPORT_PROGRESS-'
MARCXML_EXPORT_THREAD = '-MARCXML_THREAD-'
PDF_EXPORT_THREAD = '-PDF_THREAD-'
CONTLABEL_EXPORT_THREAD = '-CONTLABEL_THREAD-'
XTF_UPLOAD_THREAD = '-XTFUP_THREAD-'
XTF_INDEX_THREAD = '-XTFIND_THREAD-'
XTF_DELETE_THREAD = '-XTFDEL_THREAD-'
XTF_GETFILES_THREAD = '-XTFGET_THREAD-'
logger.remove()
logger.add(str(Path('logs', 'log_{time:YYYY-MM-DD}.log')),
format="{time}-{level}: {message}")
@logger.catch
def run_gui(defaults):
"""
Handles the GUI operation as outlined by PySimpleGUI's guidelines.
For an in-depth review on how this code is structured, see the wiki:
https://github.com/uga-libraries/ASpace_Batch_Export-Cleanup-Upload/wiki/Code-Structure#run_gui
Args:
defaults (dict): contains the data from defaults.json file, all data the user has specified as default
Returns:
None
"""
gc.disable()
sg.theme('LightBlue2')
logger.info("ArchivesSpace Login popup initiated")
as_username, as_password, as_api, close_program_as, client, asp_version, repositories, resources, xtf_version = \
get_aspace_log(defaults, xtf_checkbox=True)
logger.info(f'ArchivesSpace version: {asp_version}')
if close_program_as is True:
logger.info("User initiated closing program")
sys.exit()
pdf_broken = ["v2.6.0", "v2.7.0", "v2.7.1"]
if asp_version in pdf_broken:
asp_pdf_api = True
else:
asp_pdf_api = False
# For XTF Users Only
rid_box_len = 36
if xtf_version is True:
logger.info("XTF Login popup initiated")
xtf_username, xtf_password, xtf_hostname, xtf_remote_path, xtf_indexer_path, xtf_lazy_path, close_program_xtf \
= get_xtf_log(defaults, login=True)
if close_program_xtf is True:
logger.info("User initiated closing program")
sys.exit()
xtf_login_menu_button = 'Change XTF Login Credentials'
xtf_opt_button = 'Change XTF Options'
rid_box_len = 44
logger.info("XTF login successful")
else:
xtf_login_menu_button = '!Change XTF Login Credentials'
xtf_opt_button = '!Change XTF Options'
xtf_username, xtf_password, xtf_hostname, xtf_remote_path, xtf_indexer_path, xtf_lazy_path = "", "", "", \
"", "", ""
cleanup_defaults = ["_ADD_EADID_", "_DEL_NOTES_", "_CLN_EXTENTS_", "_ADD_CERTAIN_", "_ADD_LABEL_",
"_DEL_LANGTRAIL_", "_DEL_CONTAIN_", "_ADD_PHYSLOC_", "_DEL_ATIDS_", "_DEL_ARCHIDS_",
"_CNT_XLINKS_", "_DEL_NMSPCS_", "_DEL_ALLNS_"]
cleanup_options = [option for option, bool_val in defaults["ead_cleanup_defaults"].items() if bool_val is True]
menu_def = [['File',
['Clear Cleaned EAD Export Folder',
'---',
'Clear EAD Export Folder',
'Clear MARCXML Export Folder',
'Clear Container Label Export Folder',
'Clear PDF Export Folder',
'---',
'Reset Defaults',
'---',
'Exit']
],
['Edit',
['Change ASpace Login Credentials',
'---',
'Change EAD Cleanup Defaults',
'Change EAD Export Options',
'---',
'Change MARCXML Export Options',
'---',
'Change Container Labels Export Options',
'---',
'Change PDF Export Options',
'---',
xtf_login_menu_button,
xtf_opt_button,
]
],
['Help',
['User Manual',
'About']
]
]
ead_layout = [[sg.Button(button_text=" EXPORT ", key="_EXPORT_EAD_",
tooltip=' Export EAD.xml resources ', disabled=False),
sg.Button(button_text=" EXPORT ALL ", key="_EXPORT_ALLEADS_",
tooltip=" Export all published resources as EAD.xml files ", disabled=False)],
[sg.Text("Options", font=("Roboto", 13)),
sg.Text(" " * 123)],
[sg.Button(" EAD Export Options ", key="_EAD_OPTIONS_",
tooltip=' Choose how you would like to export resources '),
sg.Button(" Cleanup Options ", key="Change Cleanup Defaults",
tooltip=' Select what operations you want to perform on exported EAD.xml files ')],
[sg.Text("Output", font=("Roboto", 12))],
[sg.Button(button_text=" Open Cleaned EAD Exports ", key="_OPEN_CLEAN_B_",
tooltip=' Open folder where cleaned EAD.xml files are stored '),
sg.Button(button_text=" Open Raw ASpace Exports ", key="_OPEN_RAW_EXPORTS_",
tooltip=' Open folder where raw ASpace EAD.xml files are stored ')]
]
xtf_layout = [[sg.Button(button_text=" Upload Files ", key="_UPLOAD_",
tooltip=' Upload select files to XTF ', disabled=False),
sg.Text(" " * 2),
sg.Button(button_text=" Delete Files ", key="_DELETE_",
tooltip=" Delete existing files from XTF ", disabled=False),
sg.Text(" " * 2),
sg.Button(button_text=" Index Changed Records ", key="_INDEX_",
tooltip=' Run an indexing of new/updated files in XTF ', disabled=False)],
[sg.Text("Options", font=("Roboto", 13)),
sg.Text(" " * 123)],
[sg.Button(button_text=" XTF Options ", key="_XTF_OPTIONS_",
tooltip=' Select options for XTF ')]
]
marc_layout = [[sg.Button(button_text=" EXPORT ", key="_EXPORT_MARCXML_",
tooltip=' Export MARC.xml resources ', disabled=False),
sg.Button(button_text=" EXPORT ALL ", key="_EXPORT_ALLMARCXMLS_",
tooltip=" Export all published resources as MARC.xml files ", disabled=False)],
[sg.Text("Options", font=("Roboto", 13))],
[sg.Button(" MARCXML Export Options ", key="_MARCXML_OPTIONS_",
tooltip=' Choose how you would like to export resources ')],
[sg.Button(button_text=" Open Output ", key="_OPEN_MARC_DEST_",
tooltip=' Open folder where MARC.xml files are stored ')],
[sg.Text(" " * 140)]
]
contlabel_layout = [[sg.Button(button_text=" EXPORT ", key="_EXPORT_LABEL_",
tooltip=' Export container labels for resources ', disabled=False),
sg.Button(button_text=" EXPORT ALL ", key="_EXPORT_ALLCONTLABELS_", disabled=False,
tooltip=" Export all published resources as container label files ")],
[sg.Text("Options", font=("Roboto", 13))],
[sg.Button(" Labels Export Options ", key="_LABELS_OPTIONS_",
tooltip=' Choose how you would like to export container labels ')],
[sg.Button(button_text=" Open Output ", key="_OPEN_LABEL_DEST_",
tooltip=' Open folder where container label files are stored ')],
[sg.Text(" " * 140)]
]
pdf_layout = [[sg.Text("WARNING:", font=("Roboto", 18), text_color="Red", visible=asp_pdf_api),
sg.Text("Not compatible with ArchivesSpace versions 2.6.0 - 2.7.1\n"
"Your ArchivesSpace version is: {}".format(asp_version), font=("Roboto", 13),
visible=asp_pdf_api)],
[sg.Button(button_text=" EXPORT ", key="_EXPORT_PDF_",
tooltip=' Export PDF(s) for resources ', disabled=False),
sg.Button(button_text=" EXPORT ALL ", key="_EXPORT_ALLPDFS_",
tooltip=" Export all published resources as PDF files ", disabled=False)],
[sg.Text("Options", font=("Roboto", 13)),
sg.Text(" " * 125)],
[sg.Button(" PDF Export Options ", key="_PDF_OPTIONS_",
tooltip=' Choose how you would like to export resources '),
sg.Button(button_text=" Open Output ", key="_OPEN_PDF_DEST_",
tooltip=' Open folder where PDF(s) are stored ')],
[sg.Text(" " * 140)]
]
simple_layout_col1 = [[sg.Text("Enter Resource Identifiers here:", font=("Roboto", 12))],
[sg.Multiline(key="resource_id_input", size=(35, rid_box_len), focus=True,
tooltip=' Enter resource identifiers here and seperate either by comma or '
'newline (enter) ')]
]
simple_layout_col2 = [[sg.Text("Choose your export option:", font=("Roboto", 12))],
[sg.Radio("EAD", "RADIO1", key="_EXPORT_EAD_RAD_", default=True, enable_events=True),
sg.Radio("MARCXML", "RADIO1", key="_EXPORT_MARCXML_RAD_", enable_events=True),
sg.Radio("Container Labels", "RADIO1", key="_EXPORT_CONTLABS_RAD_", enable_events=True),
sg.Radio("PDF", "RADIO1", key="_EXPORT_PDF_RAD_", enable_events=True)],
[sg.Text("Choose your repository:", font=("Roboto", 12))],
[sg.DropDown([repo for repo in repositories.keys()], readonly=True,
default_value=defaults["repo_default"]["_REPO_NAME_"], key="_REPO_SELECT_",
font=("Roboto", 11),
tooltip=' Select a specific repository to export from '),
sg.Button(" SAVE ", key="_REPO_DEFAULT_",
tooltip=' Save repository as default ')],
[sg.Frame("Export EAD", ead_layout, font=("Roboto", 15), key="_EAD_LAYOUT_", visible=True),
sg.Frame("Export MARCXML", marc_layout, font=("Roboto", 15), key="_MARC_LAYOUT_",
visible=False),
sg.Frame("Export Container Labels", contlabel_layout, font=("Roboto", 15),
key="_LABEL_LAYOUT_",
visible=False),
sg.Frame("Export PDF", pdf_layout, font=("Roboto", 15), key="_PDF_LAYOUT_", visible=False)],
[sg.Frame("XTF Commands", xtf_layout, font=("Roboto", 15), key="_XTF_LAYOUT_",
visible=xtf_version)],
[sg.Text("Output Terminal:", font=("Roboto", 12),
tooltip=' Program messages are output here. To clear, select all and delete. ')],
[sg.Output(size=(80, 18), key="_output_")]
]
layout_simple = [[sg.Menu(menu_def)],
[sg.Column(simple_layout_col1), sg.Column(simple_layout_col2)]
]
window_simple = sg.Window("ArchivesSpace Batch Export-Cleanup-Upload Program", layout_simple, resizable=True)
logger.info("Initiate GUI window")
while True:
gc.collect()
event_simple, values_simple = window_simple.Read()
if event_simple == 'Cancel' or event_simple is None or event_simple == "Exit":
logger.info("User initiated closing program")
window_simple.close()
break
# ------------- CHANGE LAYOUTS SECTION -------------
if event_simple == "_EXPORT_EAD_RAD_":
logger.info("_EXPORT_EAD_RAD_ - EAD window selected")
window_simple[f'{"_EAD_LAYOUT_"}'].update(visible=True)
window_simple[f'{"_XTF_LAYOUT_"}'].update(visible=xtf_version)
window_simple[f'{"_MARC_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_LABEL_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_PDF_LAYOUT_"}'].update(visible=False)
if event_simple == "_EXPORT_MARCXML_RAD_":
logger.info("_EXPORT_MARCXML_RAD_ - MARCXML window selected")
window_simple[f'{"_EAD_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_XTF_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_MARC_LAYOUT_"}'].update(visible=True)
window_simple[f'{"_LABEL_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_PDF_LAYOUT_"}'].update(visible=False)
if event_simple == "_EXPORT_PDF_RAD_":
logger.info("_EXPORT_PDF_RAD_ - PDF window selected")
window_simple[f'{"_EAD_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_XTF_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_MARC_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_LABEL_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_PDF_LAYOUT_"}'].update(visible=True)
if event_simple == "_EXPORT_CONTLABS_RAD_":
logger.info("_EXPORT_CONTLABS_RAD_ - Container Labels window selected")
window_simple[f'{"_EAD_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_XTF_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_MARC_LAYOUT_"}'].update(visible=False)
window_simple[f'{"_LABEL_LAYOUT_"}'].update(visible=True)
window_simple[f'{"_PDF_LAYOUT_"}'].update(visible=False)
# ------------- REPOSITORY SECTION -------------
if event_simple == "_REPO_DEFAULT_":
logger.info(f'_REPO_DEFAULT_ - User saved {values_simple["_REPO_SELECT_"]} as default')
with open("defaults.json", "w") as DEFAULT:
defaults["repo_default"]["_REPO_NAME_"] = values_simple["_REPO_SELECT_"]
defaults["repo_default"]["_REPO_ID_"] = repositories[values_simple["_REPO_SELECT_"]]
json.dump(defaults, DEFAULT)
DEFAULT.close()
# ------------- EAD SECTION -------------
if event_simple == "_EXPORT_EAD_":
logger.info(f'_EXPORT_EAD_ - User initiated exporting EAD(s):\n{values_simple["resource_id_input"]}')
input_ids = values_simple["resource_id_input"]
if not values_simple["_REPO_SELECT_"]:
sg.Popup("WARNING!\nPlease select a repository")
logger.warning("User did not select a repository")
else:
if values_simple["_REPO_SELECT_"] == "Search Across Repositories (Sys Admin Only)":
sysadmin_popup = sg.PopupYesNo("WARNING!\nAre you an ArchivesSpace System Admin?\n")
if sysadmin_popup == "Yes":
logger.info("User selected - Search Across Repositories (Sys Admin Only)")
args = (input_ids, defaults, cleanup_options, repositories, client, values_simple,
window_simple,)
start_thread(get_eads, args, window_simple)
logger.info("EAD_EXPORT_THREAD started")
else:
args = (input_ids, defaults, cleanup_options, repositories, client, values_simple, window_simple,)
start_thread(get_eads, args, window_simple)
logger.info("EAD_EXPORT_THREAD started")
if event_simple == "_EXPORT_ALLEADS_":
export_all_warning = sg.PopupYesNo("WARNING!\nYou are about to export ALL the EADS in this repository"
"\n\nAre you sure you want to proceed?")
if export_all_warning == "Yes":
logger.info("_EXPORT_ALLEADS_ - User initiated exporting ALL EADs")
if not values_simple["_REPO_SELECT_"]:
sg.Popup("WARNING!\nPlease select a repository")
logger.warning("User did not select a repository")
else:
if values_simple["_REPO_SELECT_"] == "Search Across Repositories (Sys Admin Only)":
sysadmin_popup = sg.PopupYesNo("WARNING!\nAre you an ArchivesSpace System Admin?\n")
if sysadmin_popup == "Yes":
logger.info("User selected - Search Across Repositories (Sys Admin Only)")
input_ids = resources
args = (input_ids, defaults, cleanup_options, repositories, client, window_simple,)
start_thread(get_all_eads, args, window_simple)
logger.info("EAD_EXPORT_THREAD started")
else:
repo_id = repositories[values_simple["_REPO_SELECT_"]]
input_ids = {repo_id: resources[repo_id]}
args = (input_ids, defaults, cleanup_options, repositories, client, window_simple,)
start_thread(get_all_eads, args, window_simple)
logger.info("EAD_EXPORT_THREAD started")
if event_simple == "_EAD_OPTIONS_" or event_simple == "Change EAD Export Options":
get_ead_options(defaults)
if event_simple == "Change EAD Cleanup Defaults" or event_simple == "Change Cleanup Defaults":
cleanup_options = get_cleanup_defaults(cleanup_defaults, defaults)
if event_simple == "_OPEN_CLEAN_B_":
open_folder(defaults, "clean_eads", "ead_export_default", "_OUTPUT_DIR_")
if event_simple == "_OPEN_RAW_EXPORTS_":
open_folder(defaults, "source_eads", "ead_export_default", "_SOURCE_DIR_")
# ------------- MARCXML SECTION -------------
if event_simple == "_EXPORT_MARCXML_":
logger.info(f'_EXPORT_MARCXML_ - User initiated exporting MARCXMLs:\n{values_simple["resource_id_input"]}')
input_ids = values_simple["resource_id_input"]
if not values_simple["_REPO_SELECT_"]:
sg.Popup("WARNING!\nPlease select a repository")
logger.warning("User did not select a repository")
else:
if values_simple["_REPO_SELECT_"] == "Search Across Repositories (Sys Admin Only)":
sysadmin_popup = sg.PopupYesNo("WARNING!\nAre you an ArchivesSpace System Admin?\n")
if sysadmin_popup == "Yes":
logger.info("User selected - Search Across Repositories (Sys Admin Only)")
args = (input_ids, defaults, repositories, client, values_simple, window_simple,)
start_thread(get_marcxml, args, window_simple)
logger.info("MARCXML_EXPORT_THREAD started")
else:
args = (input_ids, defaults, repositories, client, values_simple, window_simple,)
start_thread(get_marcxml, args, window_simple)
logger.info("MARCXML_EXPORT_THREAD started")
if event_simple == "_EXPORT_ALLMARCXMLS_":
export_all_warning = sg.PopupYesNo("WARNING!\nYou are about to export ALL the MARCXMLs in this repository"
"\n\nAre you sure you want to proceed?")
if export_all_warning == "Yes":
logger.info("_EXPORT_ALLMARCXMLS_ - User initiated exporting ALL MARCXML(s)")
if not values_simple["_REPO_SELECT_"]:
sg.Popup("WARNING!\nPlease select a repository")
logger.warning("User did not select a repository")
else:
if values_simple["_REPO_SELECT_"] == "Search Across Repositories (Sys Admin Only)":
sysadmin_popup = sg.PopupYesNo("WARNING!\nAre you an ArchivesSpace System Admin?\n")
if sysadmin_popup == "Yes":
logger.info("User selected - Search Across Repositories (Sys Admin Only)")
input_ids = resources
args = (input_ids, defaults, repositories, client, window_simple,)
start_thread(get_all_marcxml, args, window_simple)
logger.info("MARCXML_EXPORT_THREAD started")
else:
repo_id = repositories[values_simple["_REPO_SELECT_"]]
input_ids = {repo_id: resources[repo_id]}
args = (input_ids, defaults, repositories, client, window_simple,)
start_thread(get_all_marcxml, args, window_simple)
logger.info("MARCXML_EXPORT_THREAD started")
if event_simple == "_OPEN_MARC_DEST_":
open_folder(defaults, "source_marcs", "marc_export_default", "_OUTPUT_DIR_")
if event_simple == "_MARCXML_OPTIONS_" or event_simple == "Change MARCXML Export Options":
get_marc_options(defaults)
# ------------- PDF SECTION -------------
if event_simple == "_EXPORT_PDF_":
logger.info(f'_EXPORT_PDF_ - User initiated exporting PDFs:\n{values_simple["resource_id_input"]}')
input_ids = values_simple["resource_id_input"]
if not values_simple["_REPO_SELECT_"]:
sg.Popup("WARNING!\nPlease select a repository")
logger.warning("User did not select a repository")
else:
if values_simple["_REPO_SELECT_"] == "Search Across Repositories (Sys Admin Only)":
sysadmin_popup = sg.PopupYesNo("WARNING!\nAre you an ArchivesSpace System Admin?\n")
if sysadmin_popup == "Yes":
logger.info("User selected - Search Across Repositories (Sys Admin Only)")
args = (input_ids, defaults, repositories, client, values_simple, window_simple,)
start_thread(get_pdfs, args, window_simple)
logger.info("PDF_EXPORT_THREAD started")
else:
args = (input_ids, defaults, repositories, client, values_simple, window_simple,)
start_thread(get_pdfs, args, window_simple)
logger.info("PDF_EXPORT_THREAD started")
if event_simple == "_EXPORT_ALLPDFS_":
export_all_warning = sg.PopupYesNo("WARNING!\nYou are about to export ALL the PDFs in this repository"
"\n\nAre you sure you want to proceed?")
if export_all_warning == "Yes":
logger.info("_EXPORT_ALLMARCXMLS_ - User initiated exporting ALL PDF(s)")
if not values_simple["_REPO_SELECT_"]:
sg.Popup("WARNING!\nPlease select a repository")
logger.warning("User did not select a repository")
else:
if values_simple["_REPO_SELECT_"] == "Search Across Repositories (Sys Admin Only)":
sysadmin_popup = sg.PopupYesNo("WARNING!\nAre you an ArchivesSpace System Admin?\n")
if sysadmin_popup == "Yes":
logger.info("User selected - Search Across Repositories (Sys Admin Only)")
input_ids = resources
args = (input_ids, defaults, repositories, client, window_simple,)
start_thread(get_all_pdfs, args, window_simple)
logger.info("PDF_EXPORT_THREAD started")
else:
repo_id = repositories[values_simple["_REPO_SELECT_"]]
input_ids = {repo_id: resources[repo_id]}
args = (input_ids, defaults, repositories, client, window_simple,)
start_thread(get_all_pdfs, args, window_simple)
logger.info("PDF_EXPORT_THREAD started")
if event_simple == "_OPEN_PDF_DEST_":
open_folder(defaults, "source_pdfs", "pdf_export_default", "_OUTPUT_DIR_")
if event_simple == "_PDF_OPTIONS_" or event_simple == "Change PDF Export Options":
get_pdf_options(defaults)
# ------------- CONTAINER LABEL SECTION -------------
if event_simple == "_EXPORT_LABEL_":
logger.info(f'_EXPORT_LABEL_ - User initiated exporting Container Labels:'
f'\n{values_simple["resource_id_input"]}')
input_ids = values_simple["resource_id_input"]
if not values_simple["_REPO_SELECT_"]:
sg.Popup("WARNING!\nPlease select a repository")
logger.warning("User did not select a repository")
else:
if values_simple["_REPO_SELECT_"] == "Search Across Repositories (Sys Admin Only)":
sysadmin_popup = sg.PopupYesNo("WARNING!\nAre you an ArchivesSpace System Admin?\n")
if sysadmin_popup == "Yes":
logger.info("User selected - Search Across Repositories (Sys Admin Only)")
args = (input_ids, defaults, repositories, client, values_simple, window_simple,)
start_thread(get_contlabels, args, window_simple)
logger.info("CONTLABEL_EXPORT_THREAD started")
else:
args = (input_ids, defaults, repositories, client, values_simple, window_simple,)
start_thread(get_contlabels, args, window_simple)
logger.info("CONTLABEL_EXPORT_THREAD started")
if event_simple == "_EXPORT_ALLCONTLABELS_":
export_all_warning = sg.PopupYesNo("WARNING!\nYou are about to export ALL the Container Labels in this "
"repository\n\nAre you sure you want to proceed?")
if export_all_warning == "Yes":
logger.info("_EXPORT_ALLCONTLABELS_ - User initiated exporting ALL Container Labels")
if not values_simple["_REPO_SELECT_"]:
sg.Popup("WARNING!\nPlease select a repository")
logger.warning("User did not select a repository")
else:
if values_simple["_REPO_SELECT_"] == "Search Across Repositories (Sys Admin Only)":
sysadmin_popup = sg.PopupYesNo("WARNING!\nAre you an ArchivesSpace System Admin?\n")
if sysadmin_popup == "Yes":
logger.info("User selected - Search Across Repositories (Sys Admin Only)")
input_ids = resources
args = (input_ids, defaults, repositories, client, window_simple,)
start_thread(get_all_contlabels, args, window_simple)
logger.info("CONTLABEL_EXPORT_THREAD started")
else:
repo_id = repositories[values_simple["_REPO_SELECT_"]]
input_ids = {repo_id: resources[repo_id]}
args = (input_ids, defaults, repositories, client, window_simple,)
start_thread(get_all_contlabels, args, window_simple)
logger.info("CONTLABEL_EXPORT_THREAD started")
if event_simple == "_OPEN_LABEL_DEST_":
open_folder(defaults, "source_labels", "labels_export_default", "_OUTPUT_DIR_")
if event_simple == "_LABELS_OPTIONS_" or event_simple == "Change Container Labels Export Options":
get_contlabel_options(defaults)
# ------------- EXPORT THREADS -------------
if event_simple in (EAD_EXPORT_THREAD, MARCXML_EXPORT_THREAD, PDF_EXPORT_THREAD, CONTLABEL_EXPORT_THREAD):
window_simple[f'{"_EXPORT_EAD_"}'].update(disabled=False)
window_simple[f'{"_EXPORT_ALLEADS_"}'].update(disabled=False)
window_simple[f'{"_EXPORT_MARCXML_"}'].update(disabled=False)
window_simple[f'{"_EXPORT_ALLMARCXMLS_"}'].update(disabled=False)
window_simple[f'{"_EXPORT_LABEL_"}'].update(disabled=False)
window_simple[f'{"_EXPORT_ALLCONTLABELS_"}'].update(disabled=False)
window_simple[f'{"_EXPORT_PDF_"}'].update(disabled=False)
window_simple[f'{"_EXPORT_ALLPDFS_"}'].update(disabled=False)
# The following 2 ifs - can I reference event from inside another event?
if event_simple == MARCXML_EXPORT_THREAD:
if defaults["marc_export_default"]["_OPEN_OUTPUT_"] is True:
logger.info(f'Opening MARCXML exports directory: {defaults["marc_export_default"]["_OUTPUT_DIR_"]}')
if not defaults["marc_export_default"]["_OUTPUT_DIR_"]:
filepath_marcs = str(Path.cwd().joinpath("source_marcs"))
open_file(filepath_marcs)
else:
filepath_marcs = str(Path(defaults["marc_export_default"]["_OUTPUT_DIR_"]))
open_file(filepath_marcs)
if event_simple == CONTLABEL_EXPORT_THREAD:
if defaults["labels_export_default"]["_OPEN_OUTPUT_"] is True:
logger.info(f'Opening Container Labels exports directory: '
f'{defaults["labels_export_default"]["_OUTPUT_DIR_"]}')
if not defaults["labels_export_default"]["_OUTPUT_DIR_"]:
filepath_labels = str(Path.cwd().joinpath("source_labels"))
open_file(filepath_labels)
else:
filepath_labels = str(Path(defaults["labels_export_default"]["_OUTPUT_DIR_"]))
open_file(filepath_labels)
if event_simple == PDF_EXPORT_THREAD:
if defaults["pdf_export_default"]["_OPEN_OUTPUT_"] is True:
logger.info(f'Opening PDF exports directory: {defaults["pdf_export_default"]["_OUTPUT_DIR_"]}')
if not defaults["pdf_export_default"]["_OUTPUT_DIR_"]:
filepath_pdfs = str(Path.cwd().joinpath("source_pdfs"))
open_file(filepath_pdfs)
else:
filepath_pdfs = str(Path(defaults["pdf_export_default"]["_OUTPUT_DIR_"]))
open_file(filepath_pdfs)
if event_simple == EXPORT_PROGRESS_THREAD:
sg.one_line_progress_meter("Export progress", values_simple["-EXPORT_PROGRESS-"][0],
values_simple["-EXPORT_PROGRESS-"][1], orientation='h', no_button=True)
# ------------- MENU OPTIONS SECTION -------------
# ------------------- FILE -------------------
if event_simple == "Clear Cleaned EAD Export Folder":
clear_exports(defaults, "clean_eads", "ead_export_default", "_OUTPUT_DIR_")
if event_simple == "Clear EAD Export Folder":
clear_exports(defaults, "source_eads", "ead_export_default", "_SOURCE_DIR_")
if event_simple == "Clear MARCXML Export Folder":
clear_exports(defaults, "source_marcs", "marc_export_default", "_OUTPUT_DIR_")
if event_simple == "Clear Container Label Export Folder":
clear_exports(defaults, "source_labels", "labels_export_default", "_OUTPUT_DIR_")
if event_simple == "Clear PDF Export Folder":
clear_exports(defaults, "source_pdfs", "pdf_export_default", "_OUTPUT_DIR_")
if event_simple == "Reset Defaults":
reset_defaults = sg.PopupYesNo("You are about to reset your configurations. Are you sure? \n"
"You will have to restart the program to see changes.")
if reset_defaults == "Yes":
logger.info("User initiated reseting defaults")
try:
dsetup.reset_defaults()
except Exception as e:
print(f'Error when resetting defaults: {e}')
logger.error(f'Error when resetting defaults: {e}')
# ------------------- EDIT -------------------
if event_simple == "Change ASpace Login Credentials":
logger.info(f'User initiated changing ASpace login credentials within app')
as_username, as_password, as_api, close_program_as, client, asp_version, repositories, resources, \
xtf_version = get_aspace_log(defaults, xtf_checkbox=False, as_un=as_username, as_pw=as_password,
as_ap=as_api, as_client=client, as_res=resources, as_repos=repositories,
xtf_ver=xtf_version)
if event_simple == 'Change XTF Login Credentials':
logger.info(f'User initiated changing XTF login credentials within app')
xtf_username, xtf_password, xtf_hostname, xtf_remote_path, xtf_indexer_path, xtf_lazy_path, \
close_program_xtf = get_xtf_log(defaults, login=False, xtf_un=xtf_username, xtf_pw=xtf_password,
xtf_ht=xtf_hostname, xtf_rp=xtf_remote_path, xtf_ip=xtf_indexer_path,
xtf_lp=xtf_lazy_path)
# ------------------- HELP -------------------
if event_simple == "About":
logger.info(f'User initiated About menu option')
window_about_active = True
layout_about = [
[sg.Text("Created by Corey Schmidt for the University of Georgia Libraries\n\n"
"Version: DEVELOPMENT\n\n"
"To check for the latest versions, check the Github\n", font=("Roboto", 12))],
[sg.OK(bind_return_key=True, key="_ABOUT_OK_"), sg.Button(" Check Github ", key="_CHECK_GITHUB_"),
sg.Button(" Check GUI Info ", key="_CHECK_PYPSG_")]
]
window_about = sg.Window("About this program", layout_about)
while window_about_active is True:
event_about, values_about = window_about.Read()
if event_about is None:
window_about.close()
window_about_active = False
if event_about == "_CHECK_GITHUB_":
try:
webbrowser.open("https://github.com/uga-libraries/ASpace_Batch_Export-Cleanup-Upload/releases",
new=2)
except Exception as e:
print(f'Failed to open webbrowser: {e}')
logger.error(f'Failed to open webbrowser: {e}')
if event_about == "_CHECK_PYPSG_":
try:
sg.popup_scrolled(sg.get_versions(), non_blocking=True, keep_on_top=True)
except Exception as e:
print(f'Failed to open PySimpleGUI versions popup: {e}')
logger.error(f'Failed to open PySimpleGUI versions popup: {e}')
if event_about == "_ABOUT_OK_":
window_about.close()
window_about_active = False
if event_simple == "User Manual":
try:
webbrowser.open("https://github.com/uga-libraries/ASpace_Batch_Export-Cleanup-Upload/wiki/User-Manual",
new=2)
except Exception as e:
print(f'Failed to open webbrowser: {e}')
logger.error(f'Failed to open webbrowser: {e}')
# ------------- XTF SECTION -------------------
if event_simple == "_UPLOAD_":
logger.info(f'User initiated uploading files to XTF')
window_upl_active = True
window_simple[f'{"_UPLOAD_"}'].update(disabled=True)
window_simple[f'{"_INDEX_"}'].update(disabled=True)
window_simple[f'{"_DELETE_"}'].update(disabled=True)
files_list = sort_list([ead_file for ead_file in os.listdir(defaults["xtf_default"]["xtf_local_path"])
if Path(ead_file).suffix == ".xml" or Path(ead_file).suffix == ".pdf"])
upload_options_layout = [[sg.Button(" Upload to XTF ", key="_UPLOAD_TO_XTF_", disabled=False),
sg.Text(" " * 62)],
[sg.Text("Options", font=("Roboto", 12))],
[sg.Button(" XTF Options ", key="_XTF_OPTIONS_2_")]
]
xtf_upload_layout = [[sg.Text("Files to Upload:", font=("Roboto", 14)),
sg.Text("Help", font=("Roboto", 11), text_color="blue", enable_events=True,
key="_XTFUPL_HELP_")],
[sg.Listbox(files_list, size=(50, 20), select_mode=sg.LISTBOX_SELECT_MODE_MULTIPLE,
key="_SELECT_FILES_")],
[sg.Frame("XTF Upload", upload_options_layout, font=("Roboto", 14))]]
window_upl = sg.Window("Upload Files to XTF", xtf_upload_layout)
while window_upl_active is True:
event_upl, values_upl = window_upl.Read()
if event_upl is None:
logger.info(f'User cancelled upload process')
window_simple[f'{"_UPLOAD_"}'].update(disabled=False)
window_simple[f'{"_INDEX_"}'].update(disabled=False)
window_simple[f'{"_DELETE_"}'].update(disabled=False)
window_upl.close()
window_upl_active = False
if event_upl == "_XTF_OPTIONS_2_":
logger.info(f'User selected XTF Options from Upload window: _XTF_OPTIONS_2_')
get_xtf_options(defaults)
if event_upl == "_UPLOAD_TO_XTF_":
logger.info(f'User began upload of files to XTF: _UPLOAD_TO_XTF_; Files: {values_upl}')
xtfup_thread = threading.Thread(target=upload_files_xtf, args=(defaults, xtf_hostname, xtf_username,
xtf_password, xtf_remote_path,
xtf_indexer_path, xtf_lazy_path,
values_upl, window_simple,))
xtfup_thread.start()
window_upl.close()
window_upl_active = False
if event_upl == "_XTFUPL_HELP_":
logger.info(f'User opened XTF Options Help button')
webbrowser.open(
"https://github.com/uga-libraries/ASpace_Batch_Export-Cleanup-Upload/wiki/User-Manual#upload",
new=2)
if event_simple == "_DELETE_":
logger.info(f'User initiated deleting files from XTF')
window_del_active = True
window_simple[f'{"_UPLOAD_"}'].update(disabled=True)
window_simple[f'{"_INDEX_"}'].update(disabled=True)
window_simple[f'{"_DELETE_"}'].update(disabled=True)
try:
logger.info(f'Getting remotes files from XTF')
print("Getting remote files, this may take a second...", flush=True, end="")
remote_files = get_remote_files(defaults, xtf_hostname, xtf_username, xtf_password, xtf_remote_path,
xtf_indexer_path, xtf_lazy_path)
except Exception as e:
logger.error(f'Error when getting files from XTF: {e}')
else:
print("Done")
delete_options_layout = [[sg.Button(" Delete from XTF ", key="_DELETE_XTF_", disabled=False),
sg.Text(" " * 62)],
[sg.Text("Options", font=("Roboto", 12))],
[sg.Button(" XTF Options ", key="_XTF_OPTIONS_3_")]
]
xtf_delete_layout = [[sg.Text("Files to Delete:", font=("Roboto", 14)),
sg.Text("Help", font=("Roboto", 11), text_color="blue", enable_events=True,
key="_XTFDEL_HELP_")],
[sg.Listbox(remote_files, size=(50, 20),
select_mode=sg.LISTBOX_SELECT_MODE_MULTIPLE, key="_SELECT_FILES_")],
[sg.Frame("XTF Upload", delete_options_layout, font=("Roboto", 14))]]
window_del = sg.Window("Delete Files from XTF", xtf_delete_layout)
while window_del_active is True:
event_del, values_del = window_del.Read()
if event_del is None:
logger.info(f'User cancelled deleting files from XTF')
window_simple[f'{"_UPLOAD_"}'].update(disabled=False)
window_simple[f'{"_INDEX_"}'].update(disabled=False)
window_simple[f'{"_DELETE_"}'].update(disabled=False)
window_del.close()
window_del_active = False
if event_del == "_XTF_OPTIONS_3_":
logger.info(f'User initiated getting XTF options from Delete: _XTF_OPTIONS_3_')
get_xtf_options(defaults)
if event_del == "_DELETE_XTF_":
logger.info(f'User began delete of files from XTF: _DELETE_XTF_; Files: {values_del}')
xtfdel_thread = threading.Thread(target=delete_files_xtf, args=(defaults, xtf_hostname,
xtf_username, xtf_password,
xtf_remote_path,
xtf_indexer_path, xtf_lazy_path,
values_del, window_simple,))
xtfdel_thread.start()
window_del.close()
window_del_active = False
if event_del == "_XTFDEL_HELP_":
logger.info(f'User opened XTF Options Help button')
webbrowser.open(
"https://github.com/uga-libraries/ASpace_Batch_Export-Cleanup-Upload/wiki/User-Manual#delet"
"e", new=2)
if event_simple == "_INDEX_":
logger.info(f'User initiated re-indexing: _INDEX_')
xtfind_thread = threading.Thread(target=index_xtf, args=(defaults, xtf_hostname, xtf_username, xtf_password,
xtf_remote_path, xtf_indexer_path,
xtf_lazy_path, window_simple,))
xtfind_thread.start()
window_simple[f'{"_UPLOAD_"}'].update(disabled=True)
window_simple[f'{"_INDEX_"}'].update(disabled=True)
window_simple[f'{"_DELETE_"}'].update(disabled=True)
if event_simple == "_XTF_OPTIONS_" or event_simple == "Change XTF Options":
logger.info(f'User initiated XTF options: _XTF_OPTIONS_ or Change XTF Options')
get_xtf_options(defaults)
# ---------------- XTF THREADS ----------------
if event_simple in (XTF_INDEX_THREAD, XTF_UPLOAD_THREAD, XTF_DELETE_THREAD, XTF_GETFILES_THREAD):
window_simple[f'{"_UPLOAD_"}'].update(disabled=False)
window_simple[f'{"_INDEX_"}'].update(disabled=False)
window_simple[f'{"_DELETE_"}'].update(disabled=False)
window_simple.close()
def get_aspace_log(defaults, xtf_checkbox, as_un=None, as_pw=None, as_ap=None, as_client=None, as_repos=None,
as_res=None, xtf_ver=None):
"""
Gets a user's ArchiveSpace credentials.
There are 3 components to it, the setup code, correct_creds while loop, and the window_asplog_active while loop. It
uses ASnake.client to authenticate and stay connected to ArchivesSpace. Documentation for ASnake can be found here:
https://archivesspace-labs.github.io/ArchivesSnake/html/index.html
For an in-depth review on how this code is structured, see the wiki:
https://github.com/uga-libraries/ASpace_Batch_Export-Cleanup-Upload/wiki/Code-Structure#get_aspace_log
Args:
defaults (dict): contains the data from defaults.json file, all data the user has specified as default
xtf_checkbox (bool, optional): user input that is used to display XTF-related features in the GUI
as_un (str, optional): user's ArchivesSpace username
as_pw (str, optional): user's ArchivesSpace password
as_ap (str, optional): the ArchivesSpace API URL
as_client (ASnake.client object, optional): the ArchivesSpace ASnake client for accessing and connecting to the API
as_repos (dict, optional): contains info on all the repositories for an ArchivesSpace instance, including name as the key and id # as it's value
as_res (dict, optional): contains info on all the resources for an ArchivesSpace instance, including repository name as key and list of resource ids as value
xtf_ver (bool, optional): user indicated value whether they want to display xtf features in the GUI
Returns:
as_username (str): user's ArchivesSpace username
as_password (str): user's ArchivesSpace password
as_api (str): the ArchivesSpace API URL
close_program (bool): if a user exits the popup, this will return true and end run_gui()
client (ASnake.client object): the ArchivesSpace ASnake client for accessing and connecting to the API
asp_version (str): the current version of ArchivesSpace
repositories (dict): contains info on all the repositories for an ArchivesSpace instance, including name as the key and id # as it's value
resource_ids (dict): contains info on all the resources for each repository for an ArchivesSpace instance, including repository # as the key and a list of resource #s as strings as its value
xtf_version (bool): user indicated value whether they want to display xtf features in the GUI
"""
as_username = as_un
as_password = as_pw
as_api = as_ap
client = as_client
asp_version = None
if as_repos is None:
repositories = {"Search Across Repositories (Sys Admin Only)": None}
else:
repositories = as_repos
if as_res is None:
resource_ids = {}
else:
resource_ids = as_res
xtf_version = xtf_ver
if xtf_checkbox is True:
save_button_asp = " Save and Continue "
else:
save_button_asp = " Save and Close "
window_asplog_active = True
correct_creds = False
close_program = False
while correct_creds is False:
asplog_col1 = [[sg.Text("ArchivesSpace username:", font=("Roboto", 11))],
[sg.Text("ArchivesSpace password:", font=("Roboto", 11))],
[sg.Text("ArchivesSpace API URL:", font=("Roboto", 11))]]
asplog_col2 = [[sg.InputText(focus=True, key="_ASPACE_UNAME_")],
[sg.InputText(password_char='*', key="_ASPACE_PWORD_")],
[sg.InputText(defaults["as_api"], key="_ASPACE_API_")]]
layout_asplog = [
[sg.Column(asplog_col1, key="_ASPLOG_COL1_", visible=True),
sg.Column(asplog_col2, key="_ASPLOG_COL2_", visible=True)],
[sg.Checkbox("Use XTF features of this tool", font=("Roboto", 12), key="_USE_XTF_",
default=defaults["xtf_default"]["xtf_version"], visible=xtf_checkbox)],
[sg.Button(save_button_asp, bind_return_key=True, key="_SAVE_CLOSE_LOGIN_")]
]
window_login = sg.Window("ArchivesSpace Login Credentials", layout_asplog)
while window_asplog_active is True:
event_log, values_log = window_login.Read()
if event_log == "_SAVE_CLOSE_LOGIN_":
logger.info(f'User initiated ASpace login')
connect_client = ASnakeClient(baseurl=values_log["_ASPACE_API_"],
username=values_log["_ASPACE_UNAME_"],
password=values_log["_ASPACE_PWORD_"])
try:
requests.get(values_log["_ASPACE_API_"])
except Exception as api_error:
sg.Popup("Your API credentials were entered incorrectly.\n"
"Please try again.\n\n" + api_error.__str__())
logger.error(f'Error with validating API credentials: {api_error};'
f' API: {values_log["_ASPACE_API_"]}')
else:
try:
connect_client.authorize()
except ASnakeAuthError as e:
error_message = ""
if ":" in str(e):
error_divided = str(e).split(":")
for line in error_divided:
error_message += line + "\n"
else:
error_message = str(e)
sg.Popup("Your username and/or password were entered incorrectly. Please try again.\n\n" +
error_message)
logger.error(f'Username and/or password failed: {error_message}')
else:
client = connect_client
as_username = values_log["_ASPACE_UNAME_"]
as_password = values_log["_ASPACE_PWORD_"]
as_api = values_log["_ASPACE_API_"]
xtf_version = values_log["_USE_XTF_"]
asp_version = client.get("/version").content.decode().split(" ")[1].replace("(",
"").replace(")", "")
logger.info(f'ArchivesSpace Info: \nAPI: {values_log["_ASPACE_API_"]}\nVersion: {asp_version}')
with open("defaults.json",
"w") as defaults_asp: # If connection is successful, save ASpace API in defaults.json
defaults["as_api"] = as_api
defaults["xtf_default"]["xtf_version"] = xtf_version
json.dump(defaults, defaults_asp)
defaults_asp.close()
if len(repositories) == 1: # Get repositories info
repo_results = client.get('/repositories')
repo_results_dec = json.loads(repo_results.content.decode())
for result in repo_results_dec:
uri_components = result["uri"].split("/")
repositories[result["name"]] = int(uri_components[-1])
for repository in repo_results.json(): # Get resource ids
resources = client.get(f"{repository['uri']}/resources", params={"all_ids":
True}).json()
uri_components = repository["uri"].split("/")
repository_id = int(uri_components[-1])
resource_ids[repository_id] = [resource_id for resource_id in resources]
window_asplog_active = False
correct_creds = True
if event_log is None or event_log == 'Cancel':
logger.info(f'User cancelled ASpace login')
window_login.close()
window_asplog_active = False
correct_creds = True
close_program = True
break
window_login.close()
return as_username, as_password, as_api, close_program, client, asp_version, repositories, resource_ids, xtf_version
def get_xtf_log(defaults, login=True, xtf_un=None, xtf_pw=None, xtf_ht=None, xtf_rp=None, xtf_ip=None, xtf_lp=None):
"""
Gets a user's XTF credentials.
For an in-depth review on how this code is structured, see the wiki:
https://github.com/uga-libraries/ASpace_Batch_Export-Cleanup-Upload/wiki/Code-Structure#get_xtf_log
Args:
defaults (dict): contains the data from defaults.json file, all data the user has specified as default
login (bool): determines whether window is on initial popup or within program, changes lang. of save button
xtf_un (object, optional): user's XTF username
xtf_pw (object, optional): user's XTF password
xtf_ht (object, optional): the host URL for the XTF instance
xtf_rp (object, optional): the path (folder) where a user wants their data to be stored on the XTF host
xtf_ip (object, optional): the path (file) where the website indexer is located
xtf_lp (object, optional): the path (folder) where xml lazy files are stored - for permissions updates
Returns:
xtf_username (str): user's XTF username
xtf_password (str): user's XTF password
xtf_host (str): the host URL for the XTF instance
xtf_remote_path (str): the path (folder) where a user wants their data to be stored on the XTF host
xtf_indexer_path (str): the path (file) where the website indexer is located
xtf_lazy_path (str): the path (folder) where the xml .lazy files are stored - used to update permissions
close_program (bool): if a user exits the popup, this will return true and end run_gui()
"""
xtf_username = xtf_un
xtf_password = xtf_pw
xtf_host = xtf_ht
xtf_remote_path = xtf_rp
xtf_indexer_path = xtf_ip
xtf_lazy_path = xtf_lp
if login is True:
save_button_xtf = " Save and Continue "
else:
save_button_xtf = " Save and Close "
window_xtflog_active = True
correct_creds = False
close_program = False
while correct_creds is False:
xtflog_col1 = [[sg.Text("XTF username:", font=("Roboto", 11))],
[sg.Text("XTF password:", font=("Roboto", 11))],
[sg.Text("XTF Hostname:", font=("Roboto", 11))],
[sg.Text("XTF Remote Path:", font=("Roboto", 11))],
[sg.Text("XTF Indexer Path:", font=("Roboto", 11))],
[sg.Text("XTF Lazy Index Path:", font=("Roboto", 11))]]
xtflog_col2 = [[sg.InputText(focus=True, key="_XTF_UNAME_")],
[sg.InputText(password_char='*', key="_XTF_PWORD_")],
[sg.InputText(defaults["xtf_default"]["xtf_host"], key="_XTF_HOSTNAME_")],
[sg.InputText(defaults["xtf_default"]["xtf_remote_path"], key="_XTF_REMPATH_")],
[sg.InputText(defaults["xtf_default"]["xtf_indexer_path"], key="_XTF_INDPATH_")],
[sg.InputText(defaults["xtf_default"]["xtf_lazyindex_path"], key="_XTF_LAZYPATH_")]]
layout_xtflog = [
[sg.Column(xtflog_col1), sg.Column(xtflog_col2)],
[sg.Button(save_button_xtf, bind_return_key=True, key="_SAVE_CLOSE_LOGIN_")]
]
window_xtfcred = sg.Window("XTF Login Credentials", layout_xtflog)
while window_xtflog_active is True:
event_xlog, values_xlog = window_xtfcred.Read()
logger.info(f'User initiated XTF Login credentials')
if event_xlog == "_SAVE_CLOSE_LOGIN_":
try:
remote = xup.RemoteClient(values_xlog["_XTF_HOSTNAME_"], values_xlog["_XTF_UNAME_"],
values_xlog["_XTF_PWORD_"], values_xlog["_XTF_REMPATH_"],
values_xlog["_XTF_INDPATH_"], values_xlog["_XTF_LAZYPATH_"])
remote.client = remote.connect_remote()
if remote.scp is None:
raise Exception(remote.client)
else:
xtf_username = values_xlog["_XTF_UNAME_"]
xtf_password = values_xlog["_XTF_PWORD_"]
xtf_host = values_xlog["_XTF_HOSTNAME_"]
xtf_remote_path = values_xlog["_XTF_REMPATH_"]
xtf_indexer_path = values_xlog["_XTF_INDPATH_"]
xtf_lazy_path = values_xlog["_XTF_LAZYPATH_"]
logger.info(f'XTF Info: \nHOSTNAME: {values_xlog["_XTF_HOSTNAME_"]}\n'
f'REMOTE_PATH: {values_xlog["_XTF_REMPATH_"]}\n'
f'INDEXER_PATH: {values_xlog["_XTF_INDPATH_"]}\n'
f'LAZY_INDEX_PATH: {values_xlog["_XTF_LAZYPATH_"]}')
with open("defaults.json",
"w") as defaults_xtf:
defaults["xtf_default"]["xtf_host"] = values_xlog["_XTF_HOSTNAME_"]
defaults["xtf_default"]["xtf_remote_path"] = values_xlog["_XTF_REMPATH_"]
defaults["xtf_default"]["xtf_indexer_path"] = values_xlog["_XTF_INDPATH_"]
defaults["xtf_default"]["xtf_lazyindex_path"] = values_xlog["_XTF_LAZYPATH_"]
json.dump(defaults, defaults_xtf)
defaults_xtf.close()
window_xtflog_active = False
correct_creds = True
break
except Exception as e:
sg.Popup("Your username, password, or info were entered incorrectly. Please try again.\n\n" +
str(e))
logger.error(f'XTF credentials failed.\nHostname: {values_xlog["_XTF_HOSTNAME_"]}'
f'\nRemote Path: {values_xlog["_XTF_REMPATH_"]}'
f'\nIndexer Path: {values_xlog["_XTF_INDPATH_"]}'
f'\nLazy Index Path: {values_xlog["_XTF_LAZYPATH_"]}')
window_xtflog_active = True
if event_xlog is None or event_xlog == 'Cancel':
logger.info(f'User cancelled XTF login')
window_xtfcred.close()
window_xtflog_active = False
correct_creds = True
close_program = True
break
window_xtfcred.close()
return xtf_username, xtf_password, xtf_host, xtf_remote_path, xtf_indexer_path, xtf_lazy_path, close_program
def get_eads(input_ids, defaults, cleanup_options, repositories, client, values_simple, gui_window, export_all=False):
"""
Iterates through the user input and sends them to as_export.py to fetch_results() and export_ead().
For an in-depth review on how this code is structured, see the wiki:
https://github.com/uga-libraries/ASpace_Batch_Export-Cleanup-Upload/wiki/Code-Structure#get_eads
Args:
input_ids (str): user inputs as gathered from the Resource Identifiers input box
defaults (dict): contains the data from defaults.json file, all data the user has specified as default
cleanup_options (list): options a user wants to run against an EAD.xml file after export to clean the file
These include the following:
"_ADD_EADID_", "_DEL_NOTES_", "_CLN_EXTENTS_", "_ADD_CERTAIN_", "_ADD_LABEL_", "_DEL_LANGTRAIL_",
"_DEL_CONTAIN_", "_ADD_PHYSLOC_", "_DEL_ATIDS_", "_DEL_ARCHIDS_", "_CNT_XLINKS_", "_DEL_NMSPCS_",
"_DEL_ALLNS_"
repositories (dict): repositories as listed in the ArchivesSpace instance
client (ASnake.client object): the ArchivesSpace ASnake client for accessing and connecting to the API
values_simple (dict or int): values as entered with the run_gui() function, or repository ID for export all
gui_window (PySimpleGUI Object): is the GUI window for the app. See PySimpleGUI.org for more info
export_all (bool): whether to pass URIs of all published resources to export
Returns:
None
"""
resources = []
export_counter = 0
if export_all is True:
resources = [input_ids]
repo_id = values_simple
else:
repo_id = repositories[values_simple["_REPO_SELECT_"]]
if "," in input_ids:
csep_resources = [user_input.strip() for user_input in input_ids.split(",")]
for resource in csep_resources:
linebreak_resources = resource.splitlines()
for lb_resource in linebreak_resources:
resources.append(lb_resource)
else:
resources = [user_input.strip() for user_input in input_ids.splitlines()]
for input_id in resources:
if export_all is True:
logger.info(f'Beginning EAD export: EXPORT_ALL')
resource_export = asx.ASExport(input_id, repo_id, client, defaults["ead_export_default"]["_SOURCE_DIR_"],
defaults["ead_export_default"]["_RMV_NANC_"], export_all=True)
else:
logger.info(f'Beginning EAD export: {resources}')
resource_export = asx.ASExport(input_id, repo_id, client, defaults["ead_export_default"]["_SOURCE_DIR_"],
defaults["ead_export_default"]["_RMV_NANC_"])
resource_export.fetch_results()
if resource_export.error is None:
if resource_export.result is not None:
logger.info(f'Fetched results: {resource_export.result}')
print(resource_export.result)
if export_all is False:
gui_window.write_event_value('-EXPORT_PROGRESS-', (export_counter, len(resources)))