diff --git a/vasl_templates/main_window.py b/vasl_templates/main_window.py index 63ba574..5cb4e68 100644 --- a/vasl_templates/main_window.py +++ b/vasl_templates/main_window.py @@ -28,7 +28,8 @@ class AppWebPage( QWebEnginePage ): def acceptNavigationRequest( self, url, nav_type, is_mainframe ): #pylint: disable=no-self-use,unused-argument """Called when a link is clicked.""" if url.host() in ("localhost","127.0.0.1"): - return True + if "/asl-rulebook2/" not in url.url(): # nb: asl-rulebook2 links are routed through our webapp + return True if not is_mainframe: # NOTE: We get here if we're in a child frame (e.g. Google Maps). However, we can't just ignore # these requests, because the help is also in a frame, and we want links to open in an external browser. diff --git a/vasl_templates/webapp/__init__.py b/vasl_templates/webapp/__init__.py index 048347e..eb3b961 100644 --- a/vasl_templates/webapp/__init__.py +++ b/vasl_templates/webapp/__init__.py @@ -52,6 +52,9 @@ def _init_webapp(): # NOTE: While this is generally called only once (before the first request), the test suite # can force it be done again, since it wants to reconfigure the server to test different cases. + # initialize + from vasl_templates.webapp.main import startup_msg_store #pylint: disable=cyclic-import + # start downloading files # NOTE: We used to do this in the mainline code of __init__, so that we didn't have to wait # for the first request before starting the download (useful if we are running as a standalone server). @@ -71,7 +74,6 @@ def _init_webapp(): # configure the VASL module fname = app.config.get( "VASL_MOD" ) from vasl_templates.webapp.vasl_mod import set_vasl_mod #pylint: disable=cyclic-import - from vasl_templates.webapp.main import startup_msg_store #pylint: disable=cyclic-import set_vasl_mod( fname, startup_msg_store ) # load the vehicle/ordnance listings @@ -82,6 +84,10 @@ def _init_webapp(): from vasl_templates.webapp.vo_notes import load_vo_notes #pylint: disable=cyclic-import load_vo_notes( startup_msg_store ) + # load integration data from asl-rulebook2 + from vasl_templates.webapp.vo_notes import load_asl_rulebook2_vo_note_targets #pylint: disable=cyclic-import + load_asl_rulebook2_vo_note_targets( startup_msg_store ) + # --------------------------------------------------------------------- def _load_config( fname, section ): diff --git a/vasl_templates/webapp/static/css/sortable.css b/vasl_templates/webapp/static/css/sortable.css index be33d30..bf06f9a 100644 --- a/vasl_templates/webapp/static/css/sortable.css +++ b/vasl_templates/webapp/static/css/sortable.css @@ -9,6 +9,7 @@ img.sortable-reset { vertical-align: middle ; height: 15px ; margin-right: 0.25e .sortable li:hover { cursor: pointer ; } .sortable li.ui-sortable-helper { opacity: 0.8 ; } .sortable li img.snippet { height: 1.25em ; margin: -2px -2px ; padding-left: 1em ; float: right ; } +.sortable li img.aslrb2 { height: 1.25em ; position: absolute ; bottom: -2px ; right: -2px ; opacity: 0.6 ; } .sortable ul li, .sortable ol li { margin-top: -0.75em ; } /* nb: tighten up lists in sortable2 entries */ diff --git a/vasl_templates/webapp/static/css/tabs-ob.css b/vasl_templates/webapp/static/css/tabs-ob.css index b5005e2..3415c94 100644 --- a/vasl_templates/webapp/static/css/tabs-ob.css +++ b/vasl_templates/webapp/static/css/tabs-ob.css @@ -21,7 +21,7 @@ .panel-ob_ordnance .footer { margin-top: 0.5em ; display: flex ; align-items: center ; } /* nb: the following CSS is shared by vehicles and ordnance */ -.panel-ob_vo .sortable .vo-entry { display: flex ; } +.panel-ob_vo .sortable .vo-entry { display: flex ; position: relative ; } .panel-ob_vo .sortable .vo-entry img.vasl-image { display: inline-block ; vertical-align: middle ; height: 3.25em ; margin-right: 0.5em ; } .panel-ob_vo .sortable .vo-entry.small-piece img.vasl-image { height: 2.25em ; margin-left: 0.5em ; margin-right: 0.75em ; } .panel-ob_vo .sortable .vo-entry .detail { flex-grow: 1 ; display: flex ; flex-direction: column ; justify-content: center ; } diff --git a/vasl_templates/webapp/static/images/aslrb2.png b/vasl_templates/webapp/static/images/aslrb2.png new file mode 100644 index 0000000..a63f3c7 Binary files /dev/null and b/vasl_templates/webapp/static/images/aslrb2.png differ diff --git a/vasl_templates/webapp/static/main.js b/vasl_templates/webapp/static/main.js index af5c089..d09cf33 100644 --- a/vasl_templates/webapp/static/main.js +++ b/vasl_templates/webapp/static/main.js @@ -6,6 +6,7 @@ gVehicleOrdnanceListings = {} ; gVehicleOrdnanceNotes = {} ; gVaslPieceInfo = {} ; gOnlineCounterImages = {} ; +gAslRulebook2VoNoteTargets = {} ; gWebChannelHandler = null ; gEmSize = null ; @@ -347,6 +348,16 @@ $(document).ready( function () { update_page_load_status( "template-pack" ) ; } ) ; + // get the ASL Rulebook2 vehicle/ordnance note targets + $.getJSON( gGetAslRulebook2VoNoteTargetsUrl, function(data) { + gAslRulebook2VoNoteTargets = data ; + update_page_load_status( "asl-rulebook2-vo-note-targets" ) ; + } ).fail( function( xhr, status, errorMsg ) { + if ( xhr.status != 404 ) + showErrorMsg( "Can't get the ASL Rulebook2 vehicle/ordnance note targets:
" + escapeHTML(errorMsg) + "
" ) ; + update_page_load_status( "asl-rulebook2-vo-note-targets" ) ; + } ) ; + // fixup the layout var prevHeight = [] ; $(window).resize( function() { @@ -534,7 +545,7 @@ function init_snippet_button( $btn ) gPageLoadStatus = [ "main", "app-config", "vehicle-listings", "ordnance-listings", "reset-scenario", - "vehicle-notes", "ordnance-notes", + "vehicle-notes", "ordnance-notes", "asl-rulebook2-vo-note-targets", "vasl-piece-info", "online-counter-images", "template-pack", "default-scenario" ] ; diff --git a/vasl_templates/webapp/static/utils.js b/vasl_templates/webapp/static/utils.js index 43beec2..bf0ae7e 100644 --- a/vasl_templates/webapp/static/utils.js +++ b/vasl_templates/webapp/static/utils.js @@ -459,7 +459,7 @@ function get_month_name( month ) // -------------------------------------------------------------------- -function fixup_external_links( $root ) +function fixup_external_links( $root, fixAll ) { // NOTE: We want to open externals links in a new browser window, but simply adding target="_blank" // breaks the desktop app's ability to intercept clicks (in AppWebPage.acceptNavigationRequest()), @@ -467,7 +467,7 @@ function fixup_external_links( $root ) var regex = new RegExp( "^https?://" ) ; $root.find( "a" ).each( function() { var url = $(this).attr( "href" ) ; - if ( url && url.match( regex ) ) + if ( fixAll || ( url && url.match( regex ) ) ) $(this).attr( "target", gWebChannelHandler?"":"_blank" ) ; } ) ; } diff --git a/vasl_templates/webapp/static/vo.js b/vasl_templates/webapp/static/vo.js index 72976b7..97ae1aa 100644 --- a/vasl_templates/webapp/static/vo.js +++ b/vasl_templates/webapp/static/vo.js @@ -155,6 +155,9 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap { // initialize var nat = get_player_nat( player_no ) ; + var nat_type = gTemplatePack.nationalities[ nat ].type ; + var vo_note_key = get_vo_note_key( vo_entry ) ; + var is_landing_craft = vo_note_key ? vo_note_key.substring( 0, 3 ) === "LC " : null ; var $sortable2 = $( "#ob_" + vo_type + "-sortable_" + player_no ) ; if ( seq_id === null ) { // auto-assign a sequence ID @@ -165,6 +168,43 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap seq_id = auto_assign_id( usedSeqIds, "seq_id" ) ; } + // check if an asl-rulebook2 Chapter H note is available + var aslrb2_url = null ; + var aslrb2_nat = nat ; + if ( [ "allied-minor", "axis-minor" ].indexOf( nat_type ) != -1 ) + aslrb2_nat = nat_type ; + else { + var pos = aslrb2_nat.indexOf( "~" ) ; + if ( pos > 0 ) { + // NOTE: This is a derived nationality - use the base nationality. + aslrb2_nat = aslrb2_nat.substring( 0, pos ) ; + } else { + // check for K:FW vehicles/ordnance + pos = vo_entry.id.indexOf( "/" ) ; + if ( pos > 0 ) { + var nat2 = vo_entry.id.substring( 0, pos ) ; + if ( nat2 == "kfw-uro" || nat2 == "kfw-bcfk" || nat2 == "kfw-un-common") + aslrb2_nat = "un-forces" ; + else if ( nat2 == "kfw-kpa" || nat2 == "kfw-cpva" ) + aslrb2_nat = "communist-forces" ; + } + } + } + var entries = is_landing_craft ? gAslRulebook2VoNoteTargets["landing-craft"] : gAslRulebook2VoNoteTargets[aslrb2_nat] && gAslRulebook2VoNoteTargets[aslrb2_nat][vo_type] ; + if ( entries ) { + var key = vo_note_key ; + if ( is_landing_craft ) + key = vo_note_key.substring( 3 ) ; + else { + var match = key.match( /^kfw-(un|un-common|comm):/ ) ; + if ( match ) + key = key.substring( match[0].length ) ; + } + var aslrb2_entry = entries[ key ] ; + if ( aslrb2_entry ) + aslrb2_url = gShowAslRulebook2VoNoteUrl.replace( "TARGET", aslrb2_entry.target ) ; + } + // add the specified vehicle/ordnance // NOTE: We set a fixed height for the sortable2 entries (based on the CSS settings in tabs-ob.css), // so that the vehicle/ordnance images won't get truncated if there are a lot of them. @@ -194,11 +234,10 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap "
", "" ] ; - var vo_note_key = get_vo_note_key( vo_entry ) ; var vo_note = get_vo_note( vo_type, nat, vo_note_key ) ; var vo_note_image_url = null ; if ( vo_note ) { - if ( vo_note_key.substring( 0, 3 ) === "LC " ) + if ( is_landing_craft ) vo_note_image_url = make_app_url( "/" + vo_type + "/landing-craft/note/" + vo_note_key.substring(3), true ) ; else vo_note_image_url = make_app_url( "/" + vo_type + "/" + nat + "/note/" + vo_note_key, true ) ; @@ -206,7 +245,6 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap // NOTE: Note numbers seem to be distinct across all Allied Minor or all Axis Minor vehicles/ordnance, // so if we don't find a note in a given nationality's normal vehicles/ordnance, we can get away with // just checking their corresponding common vehicles/ordnance. - var nat_type = gTemplatePack.nationalities[ nat ].type ; if ( ["allied-minor","axis-minor"].indexOf( nat_type ) !== -1 ) { vo_note = get_vo_note( vo_type, nat_type, vo_note_key ) ; if ( vo_note ) @@ -224,8 +262,16 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap data.vo_note = vo_note ; data.vo_note_image_url = vo_note_image_url ; } + if ( aslrb2_url ) { + buf.push( + "", + "", + "" + ) ; + } buf.push( "" ) ; var $content = $( buf.join("") ) ; + fixup_external_links( $content, true ) ; var $entry = $sortable2.sortable2( "add", { content: $content, data: data, diff --git a/vasl_templates/webapp/templates/index.html b/vasl_templates/webapp/templates/index.html index d0077e8..f194019 100644 --- a/vasl_templates/webapp/templates/index.html +++ b/vasl_templates/webapp/templates/index.html @@ -126,6 +126,8 @@ gImagesBaseUrl = "{{url_for('static',filename='images')}}" ; gAppConfigUrl = "{{url_for('get_app_config')}}" ; gGetStartupMsgsUrl = "{{url_for('get_startup_msgs')}}" ; gGetTemplatePackUrl = "{{url_for('get_template_pack')}}" ; +gGetAslRulebook2VoNoteTargetsUrl = "{{url_for('get_asl_rulebook2_vo_note_targets')}}" ; +gShowAslRulebook2VoNoteUrl = "{{url_for('show_asl_rulebook2_target',target='TARGET')}}" ; gGetDefaultScenarioUrl = "{{url_for('get_default_scenario')}}" ; gVehicleListingsUrl = "{{url_for('get_vehicle_listings',merge_common=1)}}" ; gOrdnanceListingsUrl = "{{url_for('get_ordnance_listings',merge_common=1)}}" ; diff --git a/vasl_templates/webapp/tests/control_tests_servicer.py b/vasl_templates/webapp/tests/control_tests_servicer.py index bb99c2c..bf98921 100644 --- a/vasl_templates/webapp/tests/control_tests_servicer.py +++ b/vasl_templates/webapp/tests/control_tests_servicer.py @@ -156,6 +156,7 @@ class ControlTestsServicer( BaseControlTestsServicer ): #pylint: disable=too-man self.setAppConfigVal( SetAppConfigValRequest( key="DISABLE_DOWNLOADED_FILES", boolVal=True ), ctx ) self.setAppConfigVal( SetAppConfigValRequest( key="DISABLE_LOCAL_ASA_INDEX_UPDATES", boolVal=True ), ctx ) self.setAppConfigVal( SetAppConfigValRequest( key="DISABLE_LFA_HOTNESS_FADEIN", boolVal=True ), ctx ) + self.deleteAppConfigVal( DeleteAppConfigValRequest( key="ASL_RULEBOOK2_BASE_URL" ), ctx ) self.deleteAppConfigVal( DeleteAppConfigValRequest( key="ALTERNATE_WEBAPP_BASE_URL" ), ctx ) # NOTE: The webapp has been reconfigured, but the client must reloaed the home page # with "?force-reinit=1", to force it to re-initialize with the new settings. diff --git a/vasl_templates/webapp/tests/fixtures/asl-rulebook2/vo-note-targets.json b/vasl_templates/webapp/tests/fixtures/asl-rulebook2/vo-note-targets.json new file mode 100644 index 0000000..776654f --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/asl-rulebook2/vo-note-targets.json @@ -0,0 +1,60 @@ +{ + +"german": { +"vehicles": { + "1": { "caption": "german/vehicles #1", "target": "gv:1" } +} +}, + +"russian": { +"ordnance": { + "2": { "caption": "russian/ordnance #2", "target": "ro:2" } +} +}, + +"allied-minor": { +"vehicles": { + "1": { "caption": "dutch/vehicles #1", "target": "dv:1" }, + "101": { "caption": "allied-minor/vehicles #101", "target": "almv:101" } +} +}, + +"axis-minor": { +"ordnance": { + "4": { "caption": "romanian/ordnance #4", "target": "ro:4" }, + "104": { "caption": "axis-minor/ordnance #104", "target": "axmo:104" } +} +}, + +"landing-craft": { + "1": { "caption": "landing-craft #1", "target": "lc:1" }, + "2": { "caption": "landing-craft #2", "target": "lc:2" } +}, + +"chinese": { +"vehicles": { + "1": { "caption": "chinese/vehicles #1", "target": "chv:1" } +} +}, + +"un-forces": { +"vehicles": { + "5": { "caption": "un-forces/vehicles #5", "target": "kfw-un:5" }, + "6": { "caption": "un-forces/vehicles #6", "target": "kfw-un:6" } +}, +"ordnance": { + "7": { "caption": "un-forces/ordnance #7", "target": "kfw-un:7" }, + "8": { "caption": "un-forces/ordnance #8", "target": "kfw-un:8" } +} +}, + +"communist-forces": { +"vehicles": { + "15": { "caption": "communist-forces/vehicles #15", "target": "kfw-comm:15" } +}, +"ordnance": { + "16": { "caption": "communist-forces/ordnance #16", "target": "kfw-comm:16" } +} +} + +} diff --git a/vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json b/vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json index fa5755d..0bb40ee 100644 --- a/vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json +++ b/vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json @@ -81,6 +81,10 @@ "type": "axis-minor" }, +"kfw-kpa": { + "display_name": "North Korean", + "ob_colors": [ "OBCOL:kfw-kpa","OBCOL2:kfw-kpa", "OBCOL-BORDER:kfw-kpa" ] +}, "kfw-cpva": { "display_name": "Communist Chinese", "ob_colors": [ "OBCOL:kfw-cpva","OBCOL2:kfw-cpva", "OBCOL-BORDER:kfw-cpva" ] diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/british.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/british.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/british.json @@ -0,0 +1 @@ +[] diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw-cpva.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw-cpva.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw-cpva.json @@ -0,0 +1 @@ +[] diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/bcfk.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/bcfk.json new file mode 100644 index 0000000..74e3437 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/bcfk.json @@ -0,0 +1,8 @@ +[ + +{ "name": "kfw british ordnance", + "note_number": "7", + "id": "kfw-bcfk/o:7" +} + +] diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/cpva.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/cpva.json new file mode 100644 index 0000000..8fe48d0 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/cpva.json @@ -0,0 +1,8 @@ +[ + +{ "name": "cpva ordnance", + "note_number": "16", + "id": "kfw-cpva/o:016" +} + +] diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/un-common.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/un-common.json new file mode 100644 index 0000000..05d9961 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/un-common.json @@ -0,0 +1,8 @@ +[ + +{ "name": "kfw common ordnance", + "note_number": "8\u2020", + "id": "kfw-un-common/o:008" +} + +] diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw-kpa.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw-kpa.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw-kpa.json @@ -0,0 +1 @@ +[] diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/kpa.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/kpa.json new file mode 100644 index 0000000..d7d9b6c --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/kpa.json @@ -0,0 +1,8 @@ +[ + +{ "name": "kpa vehicle", + "note_number": "15", + "id": "kfw-kpa/v:015" +} + +] diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/un-common.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/un-common.json new file mode 100644 index 0000000..1818d9f --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/un-common.json @@ -0,0 +1,8 @@ +[ + +{ "name": "kfw common vehicle", + "note_number": "6\u2020", + "id": "kfw-un-common/v:006" +} + +] diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/us-rok-ounc.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/us-rok-ounc.json new file mode 100644 index 0000000..8fd1779 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/us-rok-ounc.json @@ -0,0 +1,8 @@ +[ + +{ "name": "kfw us vehicle", + "note_number": "5", + "id": "kfw-uro/v:005" +} + +] diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json index 54ac820..f042288 100644 --- a/vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json +++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json @@ -1,6 +1,7 @@ [ { "name": "landing craft", + "note_number": "1", "notes": [ "A" ], "id": "sh/v:000", "gpid": [ 399, 397 ] diff --git a/vasl_templates/webapp/tests/test_aslrb2.py b/vasl_templates/webapp/tests/test_aslrb2.py new file mode 100644 index 0000000..f6acd5e --- /dev/null +++ b/vasl_templates/webapp/tests/test_aslrb2.py @@ -0,0 +1,117 @@ +""" Test integration with asl-rulebook2. """ + +import os + +from vasl_templates.webapp.tests.utils import init_webapp, find_child, find_children +from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario + +# --------------------------------------------------------------------- + +def test_chapter_h( webapp, webdriver ): + """Test links to Chapter H vehicle/ordnance notes.""" + + # initialize + webapp.control_tests.set_app_config_val( "ASL_RULEBOOK2_BASE_URL", + os.path.join( os.path.dirname(__file__), "fixtures/asl-rulebook2/vo-note-targets.json" ) + ) + init_webapp( webapp, webdriver, scenario_persistence=1 ) + base_url = "{}/asl-rulebook2/".format( webapp.base_url ) + + # test normal vehicles/ordnance + load_scenario( { + "PLAYER_1": "german", + "OB_VEHICLES_1": [ { "name": "a german vehicle" }, { "name": "another german vehicle" } ], + "PLAYER_2": "russian", + "OB_ORDNANCE_2": [ { "name": "a russian ordnance" }, { "name": "another russian ordnance" } ], + } ) + urls = _unload_aslrb2_urls( base_url ) + assert urls == [ + [ [ "gv:1", None ], [] ], + [ [], [ None, "ro:2" ] ] + ] + + # test Allied/Axis Minor vehicles/ordnance + load_scenario( { + "PLAYER_1": "dutch", + "OB_VEHICLES_1": [ { "name": "dutch vehicle" }, { "name": "common allied minor vehicle" } ], + "PLAYER_2": "romanian", + "OB_ORDNANCE_2": [ { "name": "romanian ordnance" }, { "name": "common axis minor ordnance" } ], + } ) + urls = _unload_aslrb2_urls( base_url ) + assert urls == [ + [ [ "dv:1", "almv:101" ], [] ], + [ [], [ "ro:4", "axmo:104", ] ] + ] + + # test Landing Craft + load_scenario( { + "PLAYER_1": "american", + "OB_VEHICLES_1": [ { "name": "landing craft" } ], + "PLAYER_2": "japanese", + "OB_VEHICLES_2": [ { "name": "Daihatsu" } ], + } ) + urls = _unload_aslrb2_urls( base_url ) + assert urls == [ + [ [ "lc:1" ], [] ], + [ [ "lc:2" ], [] ] + ] + + # test derived nationalities + load_scenario( { + "PLAYER_1": "chinese~gmd", + "OB_VEHICLES_1": [ { "name": "a chinese vehicle" } ], + } ) + urls = _unload_aslrb2_urls( base_url ) + assert urls == [ + [ ["chv:1"], [] ], + [ [], [] ] + ] + + # test K:FW (UN Forces) + load_scenario( { + "PLAYER_1": "american", + "OB_VEHICLES_1": [ { "name": "kfw us vehicle" }, { "name": "kfw common vehicle" } ], + "PLAYER_2": "british", + "OB_ORDNANCE_2": [ { "name": "kfw british ordnance" }, { "name": "kfw common ordnance" } ], + } ) + urls = _unload_aslrb2_urls( base_url ) + assert urls == [ + [ ["kfw-un:5","kfw-un:6"], [] ], + [ [], ["kfw-un:7","kfw-un:8"] ] + ] + + # test K:FW (Communist Forces) + load_scenario( { + "PLAYER_1": "kfw-kpa", + "OB_VEHICLES_1": [ { "name": "kpa vehicle" } ], + "PLAYER_2": "kfw-cpva", + "OB_ORDNANCE_2": [ { "name": "cpva ordnance" } ], + } ) + urls = _unload_aslrb2_urls( base_url ) + assert urls == [ + [ ["kfw-comm:15"], [] ], + [ [], ["kfw-comm:16"] ] + ] + +# --------------------------------------------------------------------- + +def _unload_aslrb2_urls( base_url ): + """Unload the URL's to the asl-rulebook2 vehicle/ordnance notes.""" + urls = [ + [ [], [] ], + [ [], [] ] + ] + for player_no in (1,2): + for vo_type_index, vo_type in enumerate(["vehicles","ordnance"]): + sortable = find_child( "#ob_{}-sortable_{}".format( vo_type, player_no ) ) + urls2 = urls[ player_no-1 ][ vo_type_index ] + for vo_entry in find_children( ".vo-entry", sortable ): + link = find_child( "a.aslrb2", vo_entry ) + if link: + url = link.get_attribute( "href" ) + if url.startswith( base_url ): + url = url[ len(base_url): ] + else: + url = None + urls2.append( url ) + return urls diff --git a/vasl_templates/webapp/vo_notes.py b/vasl_templates/webapp/vo_notes.py index d82c88c..9ef1d71 100644 --- a/vasl_templates/webapp/vo_notes.py +++ b/vasl_templates/webapp/vo_notes.py @@ -4,17 +4,22 @@ import os import io import re +import json import copy import logging +import urllib.request from collections import defaultdict -from flask import request, render_template, jsonify, send_file, abort, Response, url_for +from flask import request, render_template, jsonify, send_file, abort, redirect, Response, url_for from vasl_templates.webapp import app, globvars from vasl_templates.webapp.files import FileServer from vasl_templates.webapp.webdriver import WebDriver from vasl_templates.webapp.utils import read_text_file, resize_image_response, is_image_file, is_empty_file +_asl_rulebook2_targets = None +_asl_rulebook2_target_url_template = None + # --------------------------------------------------------------------- @app.route( "/vehicles/notes" ) @@ -351,3 +356,44 @@ def get_vo_notes_report( nat, vo_type ): NATIONALITY = nat, VO_TYPE = vo_type ) + +# --------------------------------------------------------------------- + +@app.route( "/asl-rulebook2/vo-note-targets" ) +def get_asl_rulebook2_vo_note_targets(): + """Return the Chapter H vehicle/ordnance note targets.""" + if not _asl_rulebook2_targets: + abort( 404 ) + return jsonify( _asl_rulebook2_targets ) + +@app.route( "/asl-rulebook2/" ) +def show_asl_rulebook2_target( target ): + """Show the specified asl-rulebook2 target.""" + base_url = app.config.get( "ASL_RULEBOOK2_BASE_URL" ) + if not base_url: + abort( 404 ) + url = "{}?target={}".format( base_url, target ) + return redirect( url, code=307 ) + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +def load_asl_rulebook2_vo_note_targets( msg_store ): + """Load the Chapter H vehicle/ordnance note targets.""" + global _asl_rulebook2_targets, _asl_rulebook2_target_url_template + _asl_rulebook2_targets = _asl_rulebook2_target_url_template = None + base_url = app.config.get( "ASL_RULEBOOK2_BASE_URL" ) + if not base_url: + return + try: + if os.path.isfile( base_url ): + fp = open( base_url, "r", encoding="utf-8" ) + else: + fp = urllib.request.urlopen( base_url + "/vo-note-targets" ) + _asl_rulebook2_targets = json.load( fp ) + except Exception as ex: #pylint: disable=broad-except + msg = str( getattr(ex,"reason",None) or ex ) + msg_store.warning( "Couldn't get the ASL Rulebook2 Chapter H targets: {}".format( msg ) ) + return + _asl_rulebook2_target_url_template = app.config.get( "ASL_RULEBOOK2_TARGET_URL_TEMPLATE", + base_url + "/chapter-h/{NAT}/{VO-TYPE}/{ID}" + )