Skip to content

Commit e86eedc

Browse files
Merge pull request #1030 from HL7/2025-01-gg-no-ftp-uploads
2025 01 gg no ftp uploads
2 parents 3595eeb + 867c41d commit e86eedc

File tree

8 files changed

+436
-317
lines changed

8 files changed

+436
-317
lines changed

RELEASE_NOTES.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
* Loader: Add missing packages to CQL list
2+
* Loader: fix up language/local loading sequence
3+
* Loader: fix bug for cross-version extension containing escaped [x]
4+
* Validator: Add check for duplicate ids on contained resources
5+
* Validator: fix bug looking up code system
6+
* Validator: Look for cs on other server in missed location
7+
* Validator: fix bug accessing code system from other terminology server if no version specified
8+
* Validator: validate displaylanguage when validating codes
9+
* Renderer: Possible fix for an NPE reported bu a user with no context
10+
* QA: fix bug parsing `script` tag in xhtml - handling `<` characters
11+
* QA: Tighted up handling of errors when HTML pages can't be parsed
12+
* Publication Process: remove FTP support in -go-publish (it's all git now)
13+
* Publication Process: radd support for creation phase

org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/HTMLInspector.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,8 @@ private void loadFile(String s, String base, List<ValidationMessage> messages) {
511511
} catch (FHIRFormatError | IOException e) {
512512
x = null;
513513
if (htmlName || !(e.getMessage().startsWith("Unable to Parse HTML - does not start with tag.") || e.getMessage().startsWith("Malformed XHTML"))) {
514-
messages.add(new ValidationMessage(Source.LinkChecker, IssueType.STRUCTURE, s, e.getMessage(), IssueSeverity.ERROR).setLocationLink(makeLocal(f.getAbsolutePath())));
514+
messages.add(new ValidationMessage(Source.LinkChecker, IssueType.STRUCTURE, s, e.getMessage(), IssueSeverity.ERROR).setLocationLink(makeLocal(f.getAbsolutePath())).setMessageId("HTML_PARSING_FAILED"));
515+
missingPublishBox = true;
515516
}
516517
}
517518
if (x != null) {

org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/ValidationServices.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
6565
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
6666
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
67+
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.SpecialValidationAction;
6768
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
6869
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
6970
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
@@ -492,4 +493,10 @@ public IValidationPolicyAdvisor getPolicyAdvisor() {
492493
public IValidationPolicyAdvisor setPolicyAdvisor(IValidationPolicyAdvisor policyAdvisor) {
493494
throw new Error("Not supported"); // !
494495
}
496+
497+
@Override
498+
public SpecialValidationAction policyForSpecialValidation(IResourceValidator validator, Object appContext, SpecialValidationRule rule, String stackPath, Element resource, Element element) {
499+
return SpecialValidationAction.CHECK_RULE;
500+
501+
}
495502
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package org.hl7.fhir.igtools.publisher.utils;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.util.ArrayList;
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Set;
10+
11+
import org.hl7.fhir.utilities.TextFile;
12+
import org.hl7.fhir.utilities.Utilities;
13+
import org.hl7.fhir.utilities.json.model.JsonElement;
14+
import org.hl7.fhir.utilities.json.model.JsonObject;
15+
import org.hl7.fhir.utilities.json.parser.JsonParser;
16+
17+
18+
public class HL7OrgFhirFixer {
19+
20+
public static void main(String[] args) throws IOException {
21+
File folder = new File("/Users/grahamegrieve/web/www.hl7.org.fhir");
22+
new HL7OrgFhirFixer().execute(folder.getAbsolutePath().length(), folder, true);
23+
}
24+
25+
private void execute(int rootLen, File folder, boolean root) throws IOException {
26+
boolean isSpec = isSpec(folder);
27+
if (isSpec) {
28+
System.out.print("Found Spec at "+folder.getAbsolutePath());
29+
processSpec(rootLen, folder);
30+
}
31+
boolean isEmpty = true;
32+
for (File f : folder.listFiles()) {
33+
if (f.isDirectory()) {
34+
isEmpty = false;
35+
execute(rootLen, f, false);
36+
} else if (f.getName().endsWith(".asp")) {
37+
f.delete();
38+
} else {
39+
isEmpty = false;
40+
}
41+
}
42+
if (isEmpty) {
43+
folder.delete();
44+
}
45+
}
46+
47+
private boolean isSpec(File folder) throws IOException {
48+
if (new File(Utilities.path(folder.getAbsolutePath(), "package.tgz")).exists()) {
49+
return true;
50+
}
51+
if (new File(Utilities.path(folder.getAbsolutePath(), "patient.html")).exists()) {
52+
return true;
53+
}
54+
if (new File(Utilities.path(folder.getAbsolutePath(), "patient.htm")).exists()) {
55+
return true;
56+
}
57+
return false;
58+
}
59+
60+
private void processSpec(int rootLen, File folder) throws IOException {
61+
Map<String, Map<String, String>> list = new HashMap<>();
62+
63+
scanFolder(rootLen, folder, list);
64+
65+
int size = 0;
66+
for (String t : list.keySet()) {
67+
size += list.get(t).size();
68+
String tf = Utilities.noString(t) ? folder.getAbsolutePath() : Utilities.path(folder.getAbsolutePath(), t);
69+
Utilities.createDirectoryNC(tf);
70+
Map<String, String> map = list.get(t);
71+
for (String id : map.keySet()) {
72+
String idf = Utilities.path(tf, id);
73+
Utilities.createDirectoryNC(idf);
74+
String rf = Utilities.path(idf, "index.php");
75+
TextFile.stringToFile(genRedirect(map.get(id)), rf);
76+
}
77+
}
78+
System.out.println(" "+size+" resources");
79+
}
80+
81+
private String genRedirect(String url) {
82+
String ub = url.replace(".json", "");
83+
return "<?php\r\n"+
84+
"function Redirect($url)\r\n"+
85+
"{\r\n"+
86+
" header('Location: ' . $url, true, 302);\r\n"+
87+
" exit();\r\n"+
88+
"}\r\n"+
89+
"\r\n"+
90+
"$accept = $_SERVER['HTTP_ACCEPT'];\r\n"+
91+
"if (strpos($accept, 'application/json+fhir') !== false)\r\n"+
92+
" Redirect('/fhir"+ub+".json2');\r\n"+
93+
"elseif (strpos($accept, 'application/fhir+json') !== false)\r\n"+
94+
" Redirect('/fhir"+ub+".json1');\r\n"+
95+
"elseif (strpos($accept, 'json') !== false)\r\n"+
96+
" Redirect('/fhir"+ub+".json');\r\n"+
97+
"elseif (strpos($accept, 'application/xml+fhir') !== false)\r\n"+
98+
" Redirect('/fhir"+ub+".xml2');\r\n"+
99+
"elseif (strpos($accept, 'application/fhir+xml') !== false)\r\n"+
100+
" Redirect('/fhir"+ub+".xml1');\r\n"+
101+
"elseif (strpos($accept, 'html') !== false)\r\n"+
102+
" Redirect('/fhir"+ub+".html');\r\n"+
103+
"else \r\n"+
104+
" Redirect('/fhir"+ub+".json');\r\n"+
105+
"?>\r\n"+
106+
"\r\n"+
107+
"You should not be seeing this page. If you do, PHP has failed badly.\r\n"+
108+
"\r\n";
109+
}
110+
111+
private void scanFolder(int rootLen, File folder, Map<String, Map<String, String>> list) throws IOException {
112+
for (File f : folder.listFiles()) {
113+
if (f.getName().equals("web.config")) {
114+
f.delete();
115+
} else if (f.getName().endsWith(".asp")) {
116+
f.delete();
117+
} else if (f.isDirectory()) {
118+
if (!isSpec(folder)) {
119+
scanFolder(rootLen, f, list);
120+
}
121+
} else if (f.getName().endsWith(".json") && !f.getName().contains(".canonical.")) {
122+
try {
123+
JsonElement je = JsonParser.parse(f);
124+
if (je.isJsonObject()) {
125+
JsonObject j = je.asJsonObject();
126+
if (j.has("resourceType") && j.has("id")) {
127+
String rt = j.asString("resourceType");
128+
String id = j.asString("id");
129+
String link = f.getAbsolutePath().substring(rootLen);
130+
Map<String, String> ft = makeMapForType(list, rt);
131+
ft.put(id, link);
132+
if (j.has("url")) {
133+
String url = j.asString("url");
134+
if (url.startsWith("http://hl7.org/fhir/")) {
135+
String tail = url.substring(20);
136+
if (j.has("version")) {
137+
ft.put(id+"|"+j.asString("version"), link);
138+
}
139+
if (!tail.contains("/") && !tail.contains(".")) {
140+
ft = makeMapForType(list, "");
141+
ft.put(tail, link);
142+
if (j.has("version")) {
143+
ft.put(tail+"|"+j.asString("version"), link);
144+
}
145+
}
146+
}
147+
}
148+
}
149+
}
150+
} catch (Exception e) {
151+
}
152+
}
153+
}
154+
}
155+
156+
public Map<String, String> makeMapForType(Map<String, Map<String, String>> list, String rt) {
157+
Map<String, String> ft = list.get(rt);
158+
if (ft == null) {
159+
ft = new HashMap<String, String>();
160+
list.put(rt, ft);
161+
}
162+
return ft;
163+
}
164+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package org.hl7.fhir.igtools.publisher.utils;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
8+
import org.hl7.fhir.r5.model.CanonicalResource;
9+
import org.hl7.fhir.r5.model.Resource;
10+
import org.hl7.fhir.utilities.TextFile;
11+
import org.hl7.fhir.utilities.Utilities;
12+
13+
public class HL7OrgFhirFixerForExtensions {
14+
15+
public static void main(String[] args) throws IOException {
16+
File folderRoot = new File("/Users/grahamegrieve/web/www.hl7.org.fhir");
17+
File folderExt = new File("/Users/grahamegrieve/web/www.hl7.org.fhir/extensions");
18+
new HL7OrgFhirFixerForExtensions().execute(folderRoot, folderExt);
19+
}
20+
21+
private void execute(File folderRoot, File folderExt) throws IOException {
22+
23+
scanForEmptyFolders(folderRoot);
24+
}
25+
26+
private void scanForEmptyFolders(File ff) throws IOException {
27+
boolean indexed = false;
28+
for (File f : ff.listFiles()) {
29+
if (f.isDirectory()) {
30+
if (!Utilities.existsInList(f.getName(), "assets", "assets-hist", "dist", "dist-hist", "less", "images", "less-glyphicons", "less-joyo", "html", "css",
31+
"quick", "qicore", "external", "examples", "sid", ".git", "ehrsrle")) {
32+
scanForEmptyFolders(f);
33+
}
34+
} else {
35+
if (Utilities.existsInList(f.getName(), "index.html", "index.php", "web.config", ".no.index")) {
36+
indexed = true;
37+
}
38+
if (f.getName().equals(".no.index")) {
39+
f.delete();
40+
}
41+
if (f.getName().equals("web.config")) {
42+
String s = TextFile.fileToString(f);
43+
String url = s.substring(s.indexOf("destination=")+13);
44+
url = url.substring(0, url.indexOf("\""));
45+
String rf = genRedirect(url.replace("http://hl7.org/fhir", ""));
46+
String dst = Utilities.path(ff, "index.php");
47+
TextFile.stringToFile(rf, dst);
48+
f.delete();
49+
}
50+
}
51+
}
52+
}
53+
54+
private boolean lowerCaseHtmlExists(File ff) throws IOException {
55+
String path = Utilities.path(ff.getParentFile(), ff.getName().toLowerCase()+".html");
56+
return new File(path).exists();
57+
}
58+
59+
private String genRedirect(String url) {
60+
return "<?php\r\n"+
61+
"function Redirect($url)\r\n"+
62+
"{\r\n"+
63+
" header('Location: ' . $url, true, 302);\r\n"+
64+
" exit();\r\n"+
65+
"}\r\n"+
66+
"\r\n"+
67+
"$accept = $_SERVER['HTTP_ACCEPT'];\r\n"+
68+
"if (strpos($accept, 'html') !== false)\r\n"+
69+
" Redirect('/fhir"+url+"');\r\n"+
70+
"else \r\n"+
71+
" header($_SERVER[\"SERVER_PROTOCOL\"].\" 404 Not Found\");\r\n"+
72+
"?>\r\n"+
73+
"\r\n"+
74+
"{ \"message\" : \"not-found\" }\r\n"+
75+
"\r\n";
76+
}
77+
78+
private boolean isResourceName(String name) {
79+
return Utilities.existsInList(name,
80+
"Account", "ActivityDefinition", "ActorDefinition", "AdministrableProductDefinition", "AdverseEvent", "AllergyIntolerance", "Appointment", "AppointmentResponse", "ArtifactAssessment", "AuditEvent",
81+
"Basic", "Binary", "BiologicallyDerivedProduct", "BiologicallyDerivedProductDispense", "BodySite", "BodyStructure", "Bundle", "CanonicalResource", "CapabilityStatement", "CarePlan", "CareTeam",
82+
"CatalogEntry", "ChargeItem", "ChargeItemDefinition", "Citation", "Claim", "ClaimResponse", "ClinicalImpression", "ClinicalUseDefinition", "CodeSystem", "Communication", "CommunicationRequest",
83+
"CompartmentDefinition", "Composition", "ConceptMap", "Condition", "ConditionDefinition", "Conformance", "Consent", "Contract", "Coverage", "CoverageEligibilityRequest", "CoverageEligibilityResponse",
84+
"DataElement", "DetectedIssue", "Device", "DeviceAssociation", "DeviceComponent", "DeviceDefinition", "DeviceDispense", "DeviceMetric", "DeviceRequest", "DeviceUsage", "DeviceUseRequest",
85+
"DeviceUseStatement", "DiagnosticOrder", "DiagnosticReport", "DocumentManifest", "DocumentReference", "DomainResource", "EffectEvidenceSynthesis", "EligibilityRequest", "EligibilityResponse",
86+
"Encounter", "EncounterHistory", "Endpoint", "EnrollmentRequest", "EnrollmentResponse", "EpisodeOfCare", "EventDefinition", "Evidence", "EvidenceReport", "EvidenceVariable", "ExampleScenario",
87+
"ExpansionProfile", "ExplanationOfBenefit", "FamilyMemberHistory", "Flag", "FormularyItem", "GenomicStudy", "Goal", "GraphDefinition", "Group", "GuidanceResponse", "HealthcareService", "ImagingManifest",
88+
"ImagingObjectSelection", "ImagingSelection", "ImagingStudy", "Immunization", "ImmunizationEvaluation", "ImmunizationRecommendation", "ImplementationGuide", "Ingredient", "InsurancePlan", "InventoryItem",
89+
"InventoryReport", "Invoice", "Library", "Linkage", "List", "Location", "ManufacturedItemDefinition", "Measure", "MeasureReport", "Media", "Medication", "MedicationAdministration", "MedicationDispense",
90+
"MedicationKnowledge", "MedicationOrder", "MedicationPrescription", "MedicationRequest", "MedicationStatement", "MedicationUsage", "MedicinalProduct", "MedicinalProductAuthorization", "MedicinalProductContraindication",
91+
"MedicinalProductDefinition", "MedicinalProductIndication", "MedicinalProductIngredient", "MedicinalProductInteraction", "MedicinalProductManufactured", "MedicinalProductPackaged",
92+
"MedicinalProductPharmaceutical", "MedicinalProductUndesirableEffect", "MessageDefinition", "MessageHeader", "MetadataResource", "MolecularSequence", "NamingSystem", "NutritionIntake", "NutritionOrder",
93+
"NutritionProduct", "Observation", "ObservationDefinition", "OperationDefinition", "OperationOutcome", "Order", "OrderResponse", "Organization", "OrganizationAffiliation", "PackagedProductDefinition",
94+
"Parameters", "Patient", "PaymentNotice", "PaymentReconciliation", "Permission", "Person", "PlanDefinition", "Practitioner", "PractitionerRole", "Procedure", "ProcedureRequest", "ProcessRequest",
95+
"ProcessResponse", "Provenance", "Questionnaire", "QuestionnaireResponse", "ReferralRequest", "RegulatedAuthorization", "RelatedPerson", "RequestGroup", "RequestOrchestration", "Requirements",
96+
"ResearchDefinition", "ResearchElementDefinition", "ResearchStudy", "ResearchSubject", "Resource", "RiskAssessment", "RiskEvidenceSynthesis", "Schedule", "SearchParameter", "Sequence", "ServiceDefinition",
97+
"ServiceRequest", "Slot", "Specimen", "SpecimenDefinition", "StructureDefinition", "StructureMap", "Subscription", "SubscriptionStatus", "SubscriptionTopic", "Substance", "SubstanceDefinition",
98+
"SubstanceNucleicAcid", "SubstancePolymer", "SubstanceProtein", "SubstanceReferenceInformation", "SubstanceSourceMaterial", "SubstanceSpecification", "SupplyDelivery", "SupplyRequest", "Task",
99+
"TerminologyCapabilities", "TestPlan", "TestReport", "TestScript", "Transport", "ValueSet", "VerificationResult", "VisionPrescription",
100+
101+
"Supply", "Contraindication", "CapabilityStatement2", "ClinicalUseIssue", "DiagnosticRequest", "NutritionRequest",
102+
"DecisionSupportServiceModule", "ModuleDefinition", "GuidanceRequest", "DecisionSupportRule", "ModuleMetadata", "OrderSet", "ModuleDefinition", "GuidanceRequest", "EvidenceFocus","ItemInstance"
103+
);
104+
}
105+
106+
107+
}

org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ public static List<ValidationMessage> filterMessages(List<ValidationMessage> mes
981981
Set<String> msgs = new HashSet<>();
982982
for (ValidationMessage message : messages) {
983983
boolean passesFilter = true;
984-
if (canSuppressErrors || !message.getLevel().isError()) {
984+
if ((canSuppressErrors || !message.getLevel().isError()) && (!"HTML_PARSING_FAILED".equals(message.getMessageId()))) {
985985
if (suppressedMessages.contains(message.getDisplay(), message) || suppressedMessages.contains(message.getMessage(), message) ||
986986
suppressedMessages.contains(message.getHtml(), message) || suppressedMessages.contains(message.getMessageId(), message) ||
987987
suppressedMessages.contains(message.getInvId(), message)) {

0 commit comments

Comments
 (0)