Skip to content

Commit 5225777

Browse files
jonschoningfvarose
authored andcommitted
[haskell-http-client] add support for auth methods (swagger-api#6622)
* add support for auth methods * use newtypes for required params * fix duplicate operationId issues * prevent aliasing of vendorextension references in fromOperation * add --fast to stack ci build
1 parent 9ccf9a9 commit 5225777

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+4919
-4093
lines changed

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/HaskellHttpClientCodegen.java

Lines changed: 125 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
import io.swagger.models.ModelImpl;
66
import io.swagger.models.Operation;
77
import io.swagger.models.Swagger;
8-
import io.swagger.models.properties.ArrayProperty;
9-
import io.swagger.models.properties.MapProperty;
10-
import io.swagger.models.properties.Property;
8+
import io.swagger.models.properties.*;
119

1210
import java.util.*;
1311
import java.util.regex.Pattern;
1412

1513
import org.apache.commons.io.FileUtils;
1614

15+
import io.swagger.models.auth.SecuritySchemeDefinition;
1716
import io.swagger.codegen.CliOption;
1817
import io.swagger.codegen.CodegenConstants;
1918
import io.swagger.codegen.CodegenModel;
@@ -26,6 +25,7 @@
2625
import java.io.File;
2726

2827
import org.apache.commons.lang3.StringUtils;
28+
import org.apache.commons.lang3.StringEscapeUtils;
2929
import org.apache.commons.lang3.text.WordUtils;
3030

3131
import java.util.regex.Matcher;
@@ -65,8 +65,8 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
6565
static final String MEDIA_IS_JSON = "x-mediaIsJson";
6666

6767

68-
protected Map<String, CodegenParameter> uniqueOptionalParamsByName = new HashMap<String, CodegenParameter>();
69-
protected Map<String, CodegenModel> modelNames = new HashMap<String, CodegenModel>();
68+
protected Map<String, CodegenParameter> uniqueParamsByName = new HashMap<String, CodegenParameter>();
69+
protected Set<String> typeNames = new HashSet<String>();
7070
protected Map<String, Map<String,String>> allMimeTypes = new HashMap<String, Map<String,String>>();
7171
protected Map<String, String> knownMimeDataTypes = new HashMap<String, String>();
7272
protected Map<String, Set<String>> modelMimeTypes = new HashMap<String, Set<String>>();
@@ -466,42 +466,49 @@ public String toInstantiationType(Property p) {
466466
public CodegenOperation fromOperation(String resourcePath, String httpMethod, Operation operation, Map<String, Model> definitions, Swagger swagger) {
467467
CodegenOperation op = super.fromOperation(resourcePath, httpMethod, operation, definitions, swagger);
468468

469-
op.vendorExtensions.put("x-baseOperationId", op.operationId);
469+
// prevent aliasing/sharing of operation.vendorExtensions reference
470+
op.vendorExtensions = new LinkedHashMap();
471+
472+
String operationType = toTypeName("Op", op.operationId);
473+
op.vendorExtensions.put("x-operationType", operationType);
474+
typeNames.add(operationType);
475+
470476
op.vendorExtensions.put("x-haddockPath", String.format("%s %s", op.httpMethod, op.path.replace("/", "\\/")));
471-
op.operationId = toVarName(op.operationId);
472-
op.vendorExtensions.put("x-operationType", toTypeName("Op", op.operationId));
473477
op.vendorExtensions.put("x-hasBodyOrFormParam", op.getHasBodyParam() || op.getHasFormParams());
474478

475479
for (CodegenParameter param : op.allParams) {
476-
param.vendorExtensions.put("x-operationType", WordUtils.capitalize(op.operationId));
480+
param.vendorExtensions = new LinkedHashMap(); // prevent aliasing/sharing
481+
param.vendorExtensions.put("x-operationType", operationType);
477482
param.vendorExtensions.put("x-isBodyOrFormParam", param.isBodyParam || param.isFormParam);
478483
if (!StringUtils.isBlank(param.collectionFormat)) {
479484
param.vendorExtensions.put("x-collectionFormat", mapCollectionFormat(param.collectionFormat));
480485
}
481-
if (!param.required) {
486+
if(!param.required) {
482487
op.vendorExtensions.put("x-hasOptionalParams", true);
483-
488+
}
489+
if (typeMapping.containsKey(param.dataType) || param.isPrimitiveType || param.isListContainer || param.isMapContainer || param.isFile) {
484490
String paramNameType = toTypeName("Param", param.paramName);
485491

486-
if (uniqueOptionalParamsByName.containsKey(paramNameType)) {
487-
CodegenParameter lastParam = this.uniqueOptionalParamsByName.get(paramNameType);
492+
if (uniqueParamsByName.containsKey(paramNameType)) {
493+
CodegenParameter lastParam = this.uniqueParamsByName.get(paramNameType);
488494
if (lastParam.dataType != null && lastParam.dataType.equals(param.dataType)) {
489495
param.vendorExtensions.put("x-duplicate", true);
490496
} else {
491497
paramNameType = paramNameType + param.dataType;
492-
while (modelNames.containsKey(paramNameType)) {
498+
while (typeNames.contains(paramNameType)) {
493499
paramNameType = generateNextName(paramNameType);
494500
}
501+
uniqueParamsByName.put(paramNameType, param);
495502
}
496503
} else {
497-
while (modelNames.containsKey(paramNameType)) {
504+
while (typeNames.contains(paramNameType)) {
498505
paramNameType = generateNextName(paramNameType);
499506
}
500-
uniqueOptionalParamsByName.put(paramNameType, param);
507+
uniqueParamsByName.put(paramNameType, param);
501508
}
502509

503510
param.vendorExtensions.put("x-paramNameType", paramNameType);
504-
op.vendorExtensions.put("x-hasBodyOrFormParam", op.getHasBodyParam() || op.getHasFormParams());
511+
typeNames.add(paramNameType);
505512
}
506513
}
507514
if (op.getHasPathParams()) {
@@ -572,7 +579,18 @@ public CodegenOperation fromOperation(String resourcePath, String httpMethod, Op
572579

573580
return op;
574581
}
575-
582+
583+
public List<CodegenSecurity> fromSecurity(Map<String, SecuritySchemeDefinition> schemes) {
584+
List<CodegenSecurity> secs = super.fromSecurity(schemes);
585+
for(CodegenSecurity sec : secs) {
586+
String prefix = "";
587+
if(sec.isBasic) prefix = "AuthBasic";
588+
if(sec.isApiKey) prefix = "AuthApiKey";
589+
if(sec.isOAuth) prefix = "AuthOAuth";
590+
sec.name = prefix + toTypeName("",sec.name);
591+
}
592+
return secs;
593+
}
576594

577595
@Override
578596
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
@@ -586,6 +604,7 @@ public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
586604

587605
additionalProperties.put("x-hasUnknownMimeTypes", !unknownMimeTypes.isEmpty());
588606
additionalProperties.put("x-unknownMimeTypes", unknownMimeTypes);
607+
additionalProperties.put("x-allUniqueParams", uniqueParamsByName.values());
589608

590609
return ret;
591610
}
@@ -619,12 +638,13 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
619638
public CodegenModel fromModel(String name, Model mod, Map<String, Model> allDefinitions) {
620639
CodegenModel model = super.fromModel(name, mod, allDefinitions);
621640

622-
while (uniqueOptionalParamsByName.containsKey(model.classname)) {
641+
while (typeNames.contains(model.classname)) {
623642
model.classname = generateNextName(model.classname);
624643
}
644+
typeNames.add(model.classname);
625645

626646
// From the model name, compute the prefix for the fields.
627-
String prefix = WordUtils.uncapitalize(model.classname);
647+
String prefix = StringUtils.uncapitalize(model.classname);
628648
for (CodegenProperty prop : model.vars) {
629649
prop.name = toVarName(prefix, prop.name);
630650
}
@@ -635,7 +655,6 @@ public CodegenModel fromModel(String name, Model mod, Map<String, Model> allDefi
635655
return model;
636656
}
637657

638-
modelNames.put(model.classname, model);
639658
return model;
640659
}
641660

@@ -674,6 +693,7 @@ private void processMediaType(CodegenOperation op, Map<String, String> m) {
674693
if(StringUtils.isBlank(mediaType)) return;
675694

676695
String mimeType = getMimeDataType(mediaType);
696+
typeNames.add(mimeType);
677697
m.put(MEDIA_DATA_TYPE, mimeType);
678698
if (isJsonMimeType(mediaType)) {
679699
m.put(MEDIA_IS_JSON, "true");
@@ -761,6 +781,7 @@ private static boolean isMultipartOperation(List<Map<String, String>> consumes)
761781
}
762782
return false;
763783
}
784+
764785
@Override
765786
public String toVarName(String name) {
766787
return toVarName("", name);
@@ -794,8 +815,28 @@ public String toModelFilename(String name) {
794815
return toTypeName("Model", name);
795816
}
796817
public String toTypeName(String prefix, String name) {
797-
name = camelize(underscore(sanitizeName(name)));
798-
818+
name = escapeIdentifier(prefix, camelize(sanitizeName(name)));
819+
return name;
820+
}
821+
@Override
822+
public String toOperationId(String operationId) {
823+
if (StringUtils.isEmpty(operationId)) {
824+
throw new RuntimeException("Empty method/operation name (operationId) not allowed");
825+
}
826+
operationId = escapeIdentifier("op",camelize(sanitizeName(operationId), true));
827+
String uniqueName = operationId;
828+
String uniqueNameType = toTypeName("Op", operationId);
829+
while (typeNames.contains(uniqueNameType)) {
830+
uniqueName = generateNextName(uniqueName);
831+
uniqueNameType = toTypeName("Op", uniqueName);
832+
}
833+
typeNames.add(uniqueNameType);
834+
if(!operationId.equals(uniqueName)) {
835+
LOGGER.warn("generated unique operationId `" + uniqueName + "`");
836+
}
837+
return uniqueName;
838+
}
839+
public String escapeIdentifier(String prefix, String name) {
799840
if(StringUtils.isBlank(prefix)) return name;
800841

801842
if (isReservedWord(name)) {
@@ -815,4 +856,65 @@ public String toTypeName(String prefix, String name) {
815856
static boolean isJsonMimeType(String mime) {
816857
return mime != null && JSON_MIME_PATTERN.matcher(mime).matches();
817858
}
859+
860+
@Override
861+
public String toDefaultValue(Property p) {
862+
if (p instanceof StringProperty) {
863+
StringProperty dp = (StringProperty) p;
864+
if (dp.getDefault() != null) {
865+
return "\"" + escapeText(dp.getDefault()) + "\"";
866+
}
867+
} else if (p instanceof BooleanProperty) {
868+
BooleanProperty dp = (BooleanProperty) p;
869+
if (dp.getDefault() != null) {
870+
if (dp.getDefault().toString().equalsIgnoreCase("false"))
871+
return "False";
872+
else
873+
return "True";
874+
}
875+
} else if (p instanceof DoubleProperty) {
876+
DoubleProperty dp = (DoubleProperty) p;
877+
if (dp.getDefault() != null) {
878+
return dp.getDefault().toString();
879+
}
880+
} else if (p instanceof FloatProperty) {
881+
FloatProperty dp = (FloatProperty) p;
882+
if (dp.getDefault() != null) {
883+
return dp.getDefault().toString();
884+
}
885+
} else if (p instanceof IntegerProperty) {
886+
IntegerProperty dp = (IntegerProperty) p;
887+
if (dp.getDefault() != null) {
888+
return dp.getDefault().toString();
889+
}
890+
} else if (p instanceof LongProperty) {
891+
LongProperty dp = (LongProperty) p;
892+
if (dp.getDefault() != null) {
893+
return dp.getDefault().toString();
894+
}
895+
}
896+
897+
return null;
898+
}
899+
900+
// override with any special text escaping logic
901+
@SuppressWarnings("static-method")
902+
public String escapeText(String input) {
903+
if (input == null) {
904+
return input;
905+
}
906+
907+
// remove \t, \n, \r
908+
// replace \ with \\
909+
// replace " with \"
910+
// outter unescape to retain the original multi-byte characters
911+
// finally escalate characters avoiding code injection
912+
return escapeUnsafeCharacters(
913+
StringEscapeUtils.unescapeJava(
914+
StringEscapeUtils.escapeJava(input)
915+
.replace("\\/", "/"))
916+
.replaceAll("[\\t\\n\\r]"," ")
917+
.replace("\\", "\\\\")
918+
.replace("\"", "\\\""));
919+
}
818920
}

0 commit comments

Comments
 (0)