2626
2727package cwms .cda .api .watersupply ;
2828
29+ import static cwms .cda .api .Controllers .ACCEPT ;
2930import static cwms .cda .api .Controllers .CONTRACT_NAME ;
3031import static cwms .cda .api .Controllers .CREATE ;
3132import static cwms .cda .api .Controllers .OFFICE ;
3738import com .codahale .metrics .MetricRegistry ;
3839import com .codahale .metrics .Timer ;
3940import cwms .cda .api .BaseHandler ;
40- import cwms .cda .api .Controllers ;
4141import cwms .cda .data .dao .LookupTypeDao ;
4242import cwms .cda .data .dao .watersupply .WaterSupplyAccountingDao ;
43+ import cwms .cda .data .dao .watersupply .WaterSupplyUtils ;
4344import cwms .cda .data .dto .LookupType ;
4445import cwms .cda .data .dto .StatusResponse ;
4546import cwms .cda .data .dto .watersupply .PumpTransfer ;
4647import cwms .cda .data .dto .watersupply .WaterSupplyAccounting ;
4748import cwms .cda .formatters .ContentType ;
4849import cwms .cda .formatters .Formats ;
49- import cwms .cda .data .dao .watersupply .WaterSupplyUtils ;
50- import mil .army .usace .hec .metadata .DataSetIllegalArgumentException ;
5150import io .javalin .core .util .Header ;
5251import io .javalin .http .Context ;
53- import io .javalin .http .Handler ;
5452import io .javalin .plugin .openapi .annotations .HttpMethod ;
5553import io .javalin .plugin .openapi .annotations .OpenApi ;
5654import io .javalin .plugin .openapi .annotations .OpenApiContent ;
5755import io .javalin .plugin .openapi .annotations .OpenApiParam ;
5856import io .javalin .plugin .openapi .annotations .OpenApiRequestBody ;
5957import io .javalin .plugin .openapi .annotations .OpenApiResponse ;
58+ import java .nio .charset .StandardCharsets ;
6059import java .time .Instant ;
60+ import java .util .Arrays ;
6161import java .util .List ;
6262import java .util .Map ;
6363import javax .servlet .http .HttpServletResponse ;
64+ import mil .army .usace .hec .metadata .DataSetIllegalArgumentException ;
65+ import org .apache .commons .codec .binary .Base64 ;
6466import org .jetbrains .annotations .NotNull ;
6567import org .jooq .DSLContext ;
6668
@@ -89,12 +91,18 @@ protected WaterSupplyAccountingDao getWaterSupplyAccountingDao(DSLContext dsl) {
8991 @ OpenApiParam (name = WATER_USER , description = "The water user the accounting is associated with." ,
9092 required = true ),
9193 @ OpenApiParam (name = CONTRACT_NAME , description = "The name of the contract associated with the "
92- + "accounting." , required = true ),
94+ + "accounting. For names with special characters (such as '/'), use the JSONV2 accept header "
95+ + "with a name encoded using URL-safe BASE64." , required = true ),
9396 },
9497 responses = {
9598 @ OpenApiResponse (status = STATUS_201 , description = "The pump accounting entry was created." ),
9699 @ OpenApiResponse (status = STATUS_501 , description = "Requested format is not implemented" )
97100 },
101+ headers = {
102+ @ OpenApiParam (name = ACCEPT , description = "The format of the request body. Accepts JSONV1 and JSONV2. "
103+ + "Note: JSONV2 should be used if the contract name contains special characters such as '/'. "
104+ + "In this case, the contract name should be encoded using URL-safe BASE64 encoding." )
105+ },
98106 description = "Create a new pump accounting entry associated with a water supply contract." ,
99107 path = "/projects/{office}/water-user/{water-user}/contracts/{contract-name}/accounting" ,
100108 method = HttpMethod .POST ,
@@ -106,10 +114,17 @@ public void handle(@NotNull Context ctx) {
106114 logUnusedPathParameter (ctx , WATER_USER , "Body contains required information." );
107115
108116 try (Timer .Context ignored = markAndTime (CREATE )) {
109- final String contractId = ctx .pathParam (CONTRACT_NAME );
117+ String formatHeader = ctx .header (Header .ACCEPT ) != null ? ctx .header (Header .ACCEPT ) : Formats .JSONV1 ;
118+ String contractId ;
119+ if (formatHeader != null && formatHeader .equals (Formats .JSONV2 )) {
120+ byte [] decoded = Base64 .decodeBase64 (ctx .pathParam (CONTRACT_NAME ));
121+ contractId = new String (decoded );
122+ } else {
123+ contractId = ctx .pathParam (CONTRACT_NAME );
124+ }
125+
110126 final String office = ctx .pathParam (OFFICE );
111127 DSLContext dsl = getDslContext (ctx );
112- String formatHeader = ctx .header (Header .ACCEPT ) != null ? ctx .header (Header .ACCEPT ) : Formats .JSONV1 ;
113128 ContentType contentType = Formats .parseHeader (formatHeader , WaterSupplyAccounting .class );
114129 ctx .contentType (contentType .toString ());
115130 WaterSupplyAccounting accounting = Formats .parseContent (contentType , ctx .body (),
0 commit comments