2 """Main module to migrate settings data.""" 12 from ody_migr_config
import (FEATURE_NOT_FOUND,
13 EXPECTED_EMPTY_FEATURE_CODE,
16 HCUCONNECT_MODE_CODE_MAP,
17 FEATURE_CODE_HREF_MAP,
18 DEF_MENU_ITEM_PLATFORM,
37 from ody_migr_transaction
import PgTransaction
38 from ody_migr_transaction
import pg_crsr_hndlr_decrtr
39 import ody_migr_db_handler
as pg_handler
40 from ody_migr_mmth_endpoint
import MammothMigration
41 from ody_migr_utils
import (decode_base64,
44 format_error_permission,
48 LOGGER = logging.getLogger(__name__)
54 """ Rule to generate feature code given the href and hrefExtraParams 56 Also replace the script url by adding .prg in the relevant string 57 location of the href attribute. 58 1. handle single hcu* script 59 2. handle hcuForms/some-html.html patter 60 3. handle "lnapp/AppMain" pattern 61 4. handle hcuConnect with mode attribute as extra parameter 64 _menu_dict: menu record object for this menu/sub-menu item 65 _menu_type: type of menu (D, H or S) 68 _menu_dict: _menu_dict with updated href path 72 href = EXPECTED_EMPTY_FEATURE_CODE
73 code = FEATURE_NOT_FOUND
76 if "href" in _menu_dict
and _menu_type !=
"H":
77 href = _menu_dict[
"href"].strip()
80 if "/" not in href
and href !=
"hcuConnect":
81 if href
in NO_FEATURE_CODE_HREF:
82 _menu_dict[
"href"] +=
".prg" 83 code = EXPECTED_EMPTY_FEATURE_CODE
85 elif href
in FEATURE_CODE_HREF_MAP:
86 code = FEATURE_CODE_HREF_MAP[href]
87 _menu_dict[
"href"] +=
".prg" 90 elif "hcuForms" in href:
91 code = FEATURE_CODE_HREF_MAP[
"hcuForms"]
92 _menu_dict[
"href"] = _menu_dict[
"href"].replace(
93 "hcuForms",
"hcuForms.prg")
96 elif "lnapp/AppMain" in href:
99 _menu_dict[
"href"] =
"{}/eforms/LoanApp.prg".format(SERVER_URL)
102 elif href ==
"hcuConnect" and "hrefExtraParam" in _menu_dict:
103 _menu_dict[
"href"] +=
".prg" 105 if "mode=" in _menu_dict[
"hrefExtraParam"]:
106 ext_params = _menu_dict[
"hrefExtraParam"]
107 for ext_param
in ext_params.strip().split(
"&"):
108 k_v_list = ext_param.strip().split(
"=")
109 if k_v_list[0].strip() ==
"mode":
110 mode = k_v_list[1].strip()
115 code = FEATURE_NOT_FOUND
118 elif mode
is not None and mode
in NO_MENU_LINK_MODE:
119 code = EXPECTED_EMPTY_FEATURE_CODE
122 elif mode
is not None and mode
in HCUCONNECT_MODE_CODE_MAP:
123 code = HCUCONNECT_MODE_CODE_MAP[mode]
127 return _menu_dict, code
130 return _menu_dict, href
134 """Prepare a menu record for cu_featuremenu table (all S, H and D types) 137 _menu_dict: mammoth key-valued pair of data for this menu record 138 _type: type of menu -S, D or H 139 _order: order of display of this menu/sub-menu 140 parent_id: id of the parent menu - only applicable for _type=D 141 _cu: current credit union 145 single record: list of values to be inserted in cu_featuremenu 150 assert parent_id
is None 151 if "hrefExtraParam" not in _menu_dict:
152 _menu_dict[
"hrefExtraParam"] =
"" 153 if _menu_dict[
"target"] ==
'_blank':
154 _menu_dict[
"target"] = 1
156 _menu_dict[
"target"] = 0
157 _menu_dict[
"fa-icon"] = FA_ICON_MAP.get(
158 _menu_dict[
"display"][
"en_US"],
"")
160 menu_item_attr = _menu_dict
163 assert parent_id
is None 164 menu_item_display = _menu_dict[
"display"]
166 assert "en_US" in menu_item_display
167 if (menu_item_display[
"en_US"]
in 168 [
"Communications",
"Profile",
"Disclosures"]):
175 menu_item_attr[
"display"] = menu_item_display
176 menu_item_attr[
"collapseGroup"] = collapseGroup
177 menu_item_attr[
"memAccFilter"] = memAccFilter
178 menu_item_attr[
"fa-icon"] = FA_ICON_MAP.get(
179 menu_item_display[
"en_US"],
"")
182 if (_menu_dict[
"display"][
"en_US"].lower() ==
"my moneydesktop"):
183 _menu_dict[
"target"] = 1
185 _menu_dict[
"target"] = 0
187 assert parent_id
is not None 188 _menu_dict[
"collapseGroup"] = 0
189 _menu_dict[
"memAccFilter"] =
"" 190 _menu_dict[
"fa-icon"] =
"" 191 if "hrefExtraParam" not in _menu_dict:
192 _menu_dict[
"hrefExtraParam"] =
"" 193 menu_item_attr = _menu_dict
204 get_valid_json(DEF_MENU_ITEM_PLATFORM),
205 get_valid_json(menu_item_attr)
211 @pg_crsr_hndlr_decrtr
213 """Prepare and insert menu records in the database 215 Each root-level menu type are identified as type S or H. For H, type, 216 sub-menus are sub-identified as type D. 218 For all menu/sub-menu record, it first obtains the mapping of Feature Code 219 for each record using the href and hrefExtraParam attributes. Then it 220 prepares the list of values to be inserted in the cu_featuremenu table. 222 The records must be inserted one by one as there are dependencies among the 223 records (menu_item_id column of H type should be associated with D types). 226 settings_migr_trns: PgTransaction instance handling the 228 _menu_main: menu dictionary collection 229 _cu: current credit union code 232 psycopg2.Error, psycopg2.Warning on db operation errors 235 tbl_name =
"cu_featuremenu" 244 "menu_item_platform",
250 for ind, menu_item
in enumerate(_menu_main):
258 if len(menu_item[
"detail"]) == 1:
261 standalone_menu = menu_item[
"detail"][0]
263 standalone_menu,
"S", menu_order,
None, _cu)
264 assert len(columns) == len(values)
277 menu_item,
"H", menu_order,
None, _cu)
278 assert len(columns) == len(values)
285 returning_col=
"menu_item_id" 288 parent_id = settings_migr_trns.cur.fetchone()[0]
291 for ind_sub, sub_menu
in enumerate(menu_item[
"detail"]):
294 sub_menu,
"D", menu_order, parent_id, _cu)
295 assert len(columns) == len(values)
312 _updated_branding_attrs):
313 """Update a single css attribute 315 Also write the udpate report to the report list (_report_list) 318 _m_rule: mammoth css rule eg.body 319 _m_key: mammoth css rule's one attribute: eg. color 320 update_wth: css attribute mapped value for Odyssey 321 _ody_attr: one of the keys from default 322 `$styleDefaults` associative 323 array in /app/web/monitor/ 324 scriptssiteSetColor.prg 325 _report_list: list to add attribtue changes for update 327 _updated_branding_attrs: dictionary to update attribute changes to 328 write to a branding file 331 default = BRANDING_DEFAULTS[_ody_attr]
333 if default != update_with:
334 _updated_branding_attrs[_ody_attr] = update_with
335 _report_list.append(
"[Mammoth] {} -> {} ===> [Odyssey] '{}' " 336 "(default '{}') -> {}" 337 .format(_m_rule, _m_key,
338 _ody_attr, default, update_with))
342 """Map mammoth branding css content to Odyssey 345 /app/web/monitor/scriptssiteSetColor{.prg, .data} 346 /homecu/public_html/bankingIncludes/css/brand.css 349 _brand_mammoth: dictionary of css attributes from Mammoth brand content 352 Formatted update result of what values changed from Mammoth to Odyssey 354 Example report: (it would be a compressed, single line json string to 355 make it easier to deal with it in log monitoring services.) 356 [Mammoth] .cu-primary-color -> background-color ===> 357 [Odyssey] 'headerBackground' (default '#24417A') -> '#01707B' 358 [Mammoth] .cu-primary-color -> background-color ===> 359 [Odyssey] 'footerBackground' (default '#E7E8EA') -> '#01707B' 360 [Mammoth] .cu-primary-color -> color ===> 361 [Odyssey] 'headerForeground' (default '#FFFFFF') -> '#df1313' 362 [Mammoth] .cu-primary-color -> color ===> 363 [Odyssey] 'footerForeground' (default '#777777') -> '#df1313' 364 [Mammoth] body -> font-family ===> 365 [Odyssey] 'fontFamily' (default 'Helvetica, "Helvetica Neue", 366 Arial, sans-serif') -> 'helvetica, verdana, sans-serif' 367 [Mammoth] body -> background-color ===> 368 [Odyssey] 'menuBackground' (default '#F8F8F8') -> '#eaeaea' 369 [Mammoth] body -> color ===> 370 [Odyssey] 'menuForeground' (default '#337AB7') -> '#303030' 371 [Mammoth] #content -> background ===> 372 [Odyssey] 'contentBackground' (default '#FFFFFF') -> '#fff' 373 [Mammoth] #content -> color ===> 374 [Odyssey] 'contentForeground' (default '#333333') -> '#000000' 375 [Mammoth] #content -> border ===> 376 [Odyssey] 'contentBorderWidth' (default '0px') -> '1px' 377 [Mammoth] #content -> border ===> 378 [Odyssey] 'contentBorderStyle' (default 'solid') -> 'solid' 379 [Mammoth] #content -> border ===> 380 [Odyssey] 'contentBorderColor' (default '#000000') -> '#afafaf' 381 [Mammoth] #homecuBannerArea -> background-color ===> 382 [Odyssey] 'bannerBackground' (default '#161620') -> '#333333' 383 [Mammoth] #homecuBannerArea -> height ===> 384 [Odyssey] 'bannerHeight' (default '60px') -> '60px' 385 [Mammoth] #logo_wrapper .logo_content -> background ===> 386 [Odyssey] 'logoBackground' (default 'transparent') -> '#FFFFFF' 387 [Mammoth] #logo_wrapper .logo_content -> background-size ===> 388 [Odyssey] 'logoHeightDesktop' (default '75px') -> '80px' 389 [Mammoth] .cu-secondary-color -> background-color ===> 390 [Odyssey] 'menuGroupBackground' (default '#1B8DD6') -> '#76B84B' 391 [Mammoth] .cu-secondary-color -> background-color ===> 392 [Odyssey] 'menuGroupBackgroundLighter' 393 (default '#2198E3') -> '#76B84B' 394 [Mammoth] .cu-secondary-color -> color ===> 395 [Odyssey] 'menuGroupForeground' (default '#FFFFFF') -> '#FFFFFF' 398 updated_branding_attrs = BRANDING_DEFAULTS.copy()
400 for _mammoth_rule, _mammoth_attrs
in _brand_mammoth.items():
402 if _mammoth_rule ==
"body":
404 m_attr_key =
"font-family" 408 _mammoth_attrs[m_attr_key],
411 updated_branding_attrs
414 m_attr_key =
"background-color" 418 _mammoth_attrs[m_attr_key],
421 updated_branding_attrs
428 _mammoth_attrs[m_attr_key],
431 updated_branding_attrs
434 elif _mammoth_rule ==
".cu-primary-color":
436 m_attr_key =
"background-color" 440 _mammoth_attrs[m_attr_key],
443 updated_branding_attrs
448 _mammoth_attrs[m_attr_key],
451 updated_branding_attrs
458 _mammoth_attrs[m_attr_key],
461 updated_branding_attrs
466 _mammoth_attrs[m_attr_key],
469 updated_branding_attrs
472 elif _mammoth_rule ==
"#logo_wrapper .logo_content":
475 m_attr_key =
"background" 476 m_attr_val = _mammoth_attrs[m_attr_key].split()[0].strip()
483 updated_branding_attrs
487 m_attr_key =
"background-size" 488 m_attr_val = _mammoth_attrs[m_attr_key].split()[1].strip()
495 updated_branding_attrs
498 elif _mammoth_rule ==
"#content":
500 m_attr_key =
"background" 504 _mammoth_attrs[m_attr_key],
507 updated_branding_attrs
514 _mammoth_attrs[m_attr_key],
517 updated_branding_attrs
520 m_attr_key =
"border" 521 m_attr_val = _mammoth_attrs[m_attr_key].split()
525 m_attr_val[0].strip(),
526 "contentBorderWidth",
528 updated_branding_attrs
533 m_attr_val[1].strip(),
534 "contentBorderStyle",
536 updated_branding_attrs
541 m_attr_val[2].strip(),
542 "contentBorderColor",
544 updated_branding_attrs
547 elif _mammoth_rule ==
".cu-secondary-color":
549 m_attr_key =
"background-color" 553 _mammoth_attrs[m_attr_key],
554 "menuGroupBackground",
556 updated_branding_attrs
561 _mammoth_attrs[m_attr_key],
562 "menuGroupBackgroundLighter",
564 updated_branding_attrs
571 _mammoth_attrs[m_attr_key],
572 "menuGroupForeground",
574 updated_branding_attrs
577 elif _mammoth_rule ==
"#homecuBannerArea":
579 m_attr_key =
"background-color" 583 _mammoth_attrs[m_attr_key],
586 updated_branding_attrs
589 m_attr_key =
"height" 593 _mammoth_attrs[m_attr_key],
596 updated_branding_attrs
599 return get_valid_json(update_report), updated_branding_attrs
603 """Utility function to return relevant file paths for branding content""" 604 cu_lower = _cu.lower()
605 return (BRANDING_TARGET_FILE.format(cu_lower, cu_lower),
606 BRANDING_BCK_FILE.format(cu_lower, cu_lower, cu_lower),
607 BRANDING_MMTH_FILE.format(cu_lower),
612 """Decode base64 encoded content and dump to a target file 614 - Original mammoth file is saved as BRANDING_MMTH_FILE 615 - Migrated odyssey file is saved as BRANDING_TARGET_FILE 616 - Backup odyssey file is saved as BRANDING_BCK_FILE 619 _b64_encoded_content: base64 encoded content 623 SystemExit: if IOError, NameError or PermissionError is caught 628 target_file_exist =
False 632 if os.path.exists(target_file):
633 target_file_exist =
True 634 with open(target_file,
"r")
as f_init:
635 with open(bck_file,
"w")
as f_bck:
636 f_bck.write(f_init.read())
639 with open(target_file,
'w')
as f_main:
641 str_content = decode_base64(_b64_encoded_content)
644 with open(mmth_file,
"w")
as f_mmth:
645 f_mmth.write(str_content)
648 css_content_list = str_content.split(
"/* ** CUSTOM ** */")
651 main_branding_css = css_content_list[0].strip()
655 brand_mammoth = custom_css_parser(main_branding_css)
662 LOGGER.debug(
"[BRANDING] Mammoth to Ody changes:\t{}".format(
666 rendered_template_css =
"" 667 with open(template_file,
"r")
as f_template:
668 rendered_template_css = f_template.read()
669 for k, v
in updated_branding_attrs.items():
670 rendered_template_css = rendered_template_css.replace(
674 f_main.write(rendered_template_css)
677 except (IOError, NameError)
as err:
679 if target_file_exist
and os.path.exists(bck_file):
680 os.rename(bck_file, target_file)
682 formatted_err = format_error_permission(err,
"")
683 LOGGER.error(formatted_err)
684 raise SystemExit(formatted_err)
690 """Migrate settings data obtained from Mammoth to Odyssey. 693 settings_migr_trns: settings migration transaction instance 694 _response (dict): python dictionary represetntation of the 695 response json dictionary from mammoth 696 _verbose: verbosity of log 697 _cu: current credit union code 701 progress_dict = {
"completed": 0,
"total": 4}
703 cuadmin_coll = _response[
"data"][
"cuadmin"]
704 where_cu_condition = {
"cu": _cu}
705 assert type(cuadmin_coll) == list
706 for cuadmin_record
in cuadmin_coll:
707 cuadmin_record[
"settings"] = get_valid_json({
"profile" :
"DEF"})
708 if _cu.lower().strip() ==
"cruisecu" and os.getenv(
'DEVMODE') ==
'1':
709 cuadmin_record[
"liveserver"] = \
710 "https://int-apl0.homecu.net/hculive/xenia-homecu-faux.mp" 712 cuadmin_record[
"liveserver"] =
"#" 717 where_conditions={
"cu": _cu},
718 collection=cuadmin_coll
725 where_conditions=where_cu_condition
728 progress_dict[
"completed"] += 1
729 log_progress(progress_dict)
732 custom_content_coll = _response[
"data"][
"custom-content"]
733 assert type(custom_content_coll) == list
738 where_conditions=where_cu_condition,
739 collection=custom_content_coll
746 where_conditions=where_cu_condition
749 progress_dict[
"completed"] += 1
750 log_progress(progress_dict)
753 menu_content_coll = _response[
"data"][
"menu"]
754 assert type(menu_content_coll) == list
763 where_conditions=where_cu_condition
766 progress_dict[
"completed"] += 1
767 log_progress(progress_dict)
770 mmth_lnappconfig_coll = _response[
"data"][
"lnappconfig"]
771 for lnappconfig_record
in mmth_lnappconfig_coll:
772 dict_lnapp_config= json.loads(lnappconfig_record[
'appconfig'])
776 subdomain = os.getenv(
"TICKET_DOMAIN",
"localhost:8000")
777 subdomain = subdomain
if subdomain.strip() !=
"" else "localhost:8000" 778 dict_lnapp_config[
"configLoanCSS"] = re.sub(
"(.*)(www[356]{1}\.homecu.net)(.*)",
779 "\g<1>{}\g<3>".format(subdomain),
780 dict_lnapp_config[
"configLoanCSS"])
783 lnappconfig_record[
'appconfig'] = get_valid_json(dict_lnapp_config)
788 collection=mmth_lnappconfig_coll
791 progress_dict[
"completed"] += 1
792 log_progress(progress_dict)
796 branding_content = _response[
"data"][
"branding"]
801 LOGGER.info(
"Branding content migrated!")
805 settings_migr_trns.commit()
809 @pg_crsr_hndlr_decrtr
811 """Cleanup settings content 813 If kwargs.get('commit_later') flag is True, we do not commit the 814 transaction here (and only cleanup database tables, not the files), 815 meaning that the the cleanup may have been executed before actual 816 migration. If commit_later flag is False, we commit the transaction 817 here and proceed with the file cleanup. 820 cleanup_transaction: instance of PgTransaction to which this cleanup 822 _cu: current credit union code 824 commit_later: flag to commit transaction later or now 827 SystemExit: if IOError, NameError or PermissionError is caught 828 psycopg2.Error, psycopg2.Warning on db operation errors 830 commit_later = kwargs.get(
"commit_later",
False)
833 clean_up_tables = [
"cucmsfrags",
"cuadmin",
"cu_featuremenu",
"lnappconfig"]
834 for tbl
in clean_up_tables:
838 where_conditions={
"cu": _cu}
848 if os.path.exists(target_file):
849 os.remove(target_file)
850 if os.path.exists(bck_file):
852 if os.path.exists(mmth_file):
855 LOGGER.info(
"Branding content deleted.")
858 cleanup_transaction.commit()
867 @pg_crsr_hndlr_decrtr
869 """Entry point to the settings migration. 872 cu: current credit union code 873 server: Mammoth endpoint server 874 action: one of the migration options to be 875 performed on settings data category 876 user: Mammoth monitor username 877 passwd: Mammoth monitor password 878 verbose: level of verbosity 881 psycopg2.Error, psycopg2.Warning on db operation errors 884 with pg_handler.PGSession()
as conn:
885 with conn.cursor()
as cur:
889 do_not_exist_list) = tables_exist_transaction(
895 if not tables_exist_flag:
896 error_msg = (
"Stopping migration. Following table" 897 " schemas do not exist: {}").format(
898 get_valid_json(
", ".join(do_not_exist_list)))
899 LOGGER.error(error_msg)
900 raise SystemExit(error_msg)
903 "All required target tables exist! Continuing migration..")
906 if action == ACTION_OPT_MIGRATE:
915 settings_migration.run()
917 LOGGER.info(
"Initiating migrating response data to odyssey")
918 with pg_handler.PGSession()
as conn:
919 with conn.cursor()
as cur:
935 "Running initial db cleanup before migration...")
940 settings_migration.response,
951 LOGGER.info(
"Settings Migration Completed!")
954 elif action == ACTION_OPT_CLEAN:
955 with pg_handler.PGSession()
as conn:
956 with conn.cursor()
as cur:
960 LOGGER.info(
"Settings cleanup completed!")
963 elif action == ACTION_OPT_SUMMARY:
964 with pg_handler.PGSession()
as conn:
965 with conn.cursor()
as cur:
969 settings_summary_transaction(
def _brnd_update_styles(_brand_mammoth)
def _menu_prepare_record(_menu_dict, _type, _order, parent_id, _cu)
def _menu_get_feature_code(_menu_dict, _menu_type)
def migrate_settings(cu, server, action, user, passwd, verbose)
def cleanup_settings(cleanup_transaction, _cu, **kwargs)
def menu_insert_cu_featuremenu(settings_migr_trns, _menu_main, _cu)
def _brnd_update_attr(_m_rule, _m_key, update_with, _ody_attr, _report_list, _updated_branding_attrs)
def _brnd_migrate_content(_b64_encoded_content, _cu)
def _get_branding_fnames(_cu)
def move_settings(settings_migr_trns, _response, _verbose, _cu)