Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 53 additions & 50 deletions ai_summary/WEBUI_PROPS_ALPHABETICAL_LIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,56 +26,57 @@ These properties can be:
13. `webui_developer_user_invitation_email_text`
14. `webui_direct_login_documentation_url`
15. `webui_dummy_user_logins`
16. `webui_faq_data_text`
17. `webui_faq_email`
18. `webui_faq_url`
19. `webui_favicon_link_url`
20. `webui_featured_sdks_external_link`
21. `webui_footer2_logo_left_url`
22. `webui_footer2_middle_text`
23. `webui_get_started_text`
24. `webui_header_logo_left_url`
25. `webui_header_logo_right_url`
26. `webui_index_page_about_section_background_image_url`
27. `webui_index_page_about_section_text`
28. `webui_legal_notice_html_text`
29. `webui_login_button_text`
30. `webui_login_page_instruction_title`
31. `webui_login_page_special_instructions`
32. `webui_main_faq_external_link`
33. `webui_main_partners`
34. `webui_main_style_sheet`
35. `webui_oauth_1_documentation_url`
36. `webui_oauth_2_documentation_url`
37. `webui_obp_cli_url`
38. `webui_override_style_sheet`
39. `webui_page_title_prefix`
40. `webui_post_consumer_registration_more_info_text`
41. `webui_post_consumer_registration_more_info_url`
42. `webui_post_consumer_registration_submit_button_value`
43. `webui_post_user_invitation_submit_button_value`
44. `webui_post_user_invitation_terms_and_conditions_checkbox_value`
45. `webui_privacy_policy`
46. `webui_privacy_policy_url`
47. `webui_sandbox_introduction`
48. `webui_sdks_url`
49. `webui_show_dummy_user_tokens`
50. `webui_signup_body_password_repeat_text`
51. `webui_signup_form_submit_button_value`
52. `webui_signup_form_title_text`
53. `webui_social_handle`
54. `webui_social_logo_url`
55. `webui_social_title`
56. `webui_social_url`
57. `webui_subscriptions_button_text`
58. `webui_subscriptions_invitation_text`
59. `webui_subscriptions_url`
60. `webui_support_email`
61. `webui_support_platform_url`
62. `webui_terms_and_conditions`
63. `webui_top_text`
64. `webui_user_invitation_notice_text`
65. `webui_vendor_support_html_url`
16. `webui_external_consumer_registration_url`
17. `webui_faq_data_text`
18. `webui_faq_email`
19. `webui_faq_url`
20. `webui_favicon_link_url`
21. `webui_featured_sdks_external_link`
22. `webui_footer2_logo_left_url`
23. `webui_footer2_middle_text`
24. `webui_get_started_text`
25. `webui_header_logo_left_url`
26. `webui_header_logo_right_url`
27. `webui_index_page_about_section_background_image_url`
28. `webui_index_page_about_section_text`
29. `webui_legal_notice_html_text`
30. `webui_login_button_text`
31. `webui_login_page_instruction_title`
32. `webui_login_page_special_instructions`
33. `webui_main_faq_external_link`
34. `webui_main_partners`
35. `webui_main_style_sheet`
36. `webui_oauth_1_documentation_url`
37. `webui_oauth_2_documentation_url`
38. `webui_obp_cli_url`
39. `webui_override_style_sheet`
40. `webui_page_title_prefix`
41. `webui_post_consumer_registration_more_info_text`
42. `webui_post_consumer_registration_more_info_url`
43. `webui_post_consumer_registration_submit_button_value`
44. `webui_post_user_invitation_submit_button_value`
45. `webui_post_user_invitation_terms_and_conditions_checkbox_value`
46. `webui_privacy_policy`
47. `webui_privacy_policy_url`
48. `webui_sandbox_introduction`
49. `webui_sdks_url`
50. `webui_show_dummy_user_tokens`
51. `webui_signup_body_password_repeat_text`
52. `webui_signup_form_submit_button_value`
53. `webui_signup_form_title_text`
54. `webui_social_handle`
55. `webui_social_logo_url`
56. `webui_social_title`
57. `webui_social_url`
58. `webui_subscriptions_button_text`
59. `webui_subscriptions_invitation_text`
60. `webui_subscriptions_url`
61. `webui_support_email`
62. `webui_support_platform_url`
63. `webui_terms_and_conditions`
64. `webui_top_text`
65. `webui_user_invitation_notice_text`
66. `webui_vendor_support_html_url`

---

Expand All @@ -101,6 +102,7 @@ These properties can be:
- `webui_api_explorer_url`
- `webui_api_manager_url`
- `webui_direct_login_documentation_url`
- `webui_external_consumer_registration_url`
- `webui_faq_url`
- `webui_featured_sdks_external_link`
- `webui_main_faq_external_link`
Expand Down Expand Up @@ -143,6 +145,7 @@ These properties can be:
- `webui_user_invitation_notice_text`

### Consumer Registration
- `webui_external_consumer_registration_url` (defaults to `webui_api_explorer_url` + `/consumers/register`)
- `webui_post_consumer_registration_more_info_text`
- `webui_post_consumer_registration_more_info_url`
- `webui_post_consumer_registration_submit_button_value`
Expand Down
6 changes: 6 additions & 0 deletions obp-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,12 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.7.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/tools.jackson.dataformat/jackson-dataformat-yaml -->
<dependency>
<groupId>tools.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>3.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/scala/bootstrap/liftweb/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ class Boot extends MdcLoggable {
Menu.i("debug-webui") / "debug" / "debug-webui",
Menu.i("Consumer Admin") / "admin" / "consumers" >> Admin.loginFirst >> LocGroup("admin")
submenus(Consumer.menus : _*),
Menu("Consumer Registration", Helper.i18n("consumer.registration.nav.name")) / "consumer-registration" >> AuthUser.loginFirst,

Menu("Consent Screen", Helper.i18n("consent.screen")) / "consent-screen" >> AuthUser.loginFirst,
Menu("Dummy user tokens", "Get Dummy user tokens") / "dummy-user-tokens" >> AuthUser.loginFirst,

Expand Down
41 changes: 30 additions & 11 deletions obp-api/src/main/scala/code/actorsystem/ObpActorConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ import code.util.Helper
object ObpActorConfig {

val localHostname = "127.0.0.1"
def localPort = Helper.findAvailablePort()
def localPort = {
val systemPort = APIUtil.getPropsAsIntValue("pekko.remote.artery.canonical.port", 0)
if (systemPort == 0) {
Helper.findAvailablePort()
} else {
systemPort
}
}

val akka_loglevel = APIUtil.getPropsValue("remotedata.loglevel").openOr("INFO")

Expand Down Expand Up @@ -64,12 +71,16 @@ object ObpActorConfig {
}
}
remote {
enabled-transports = ["org.apache.pekko.remote.netty.tcp"]
netty {
tcp {
send-buffer-size = 50000000
receive-buffer-size = 50000000
maximum-frame-size = 52428800
artery {
transport = tcp
canonical.hostname = """ + localHostname + """
canonical.port = 0
bind.hostname = """ + localHostname + """
bind.port = 0
advanced {
maximum-frame-size = 52428800
buffer-pool-size = 128
maximum-large-frame-size = 52428800
}
}
}
Expand All @@ -80,17 +91,25 @@ object ObpActorConfig {
s"""
${commonConf}
pekko {
remote.netty.tcp.hostname = ${localHostname}
remote.netty.tcp.port = 0
remote.artery {
canonical.hostname = ${localHostname}
canonical.port = 0
bind.hostname = ${localHostname}
bind.port = 0
}
}
"""

val localConf =
s"""
${commonConf}
pekko {
remote.netty.tcp.hostname = ${localHostname}
remote.netty.tcp.port = ${localPort}
remote.artery {
canonical.hostname = ${localHostname}
canonical.port = ${localPort}
bind.hostname = ${localHostname}
bind.port = ${localPort}
}
}
"""
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package code.api.ResourceDocs1_4_0

import code.api.Constant.HostName
import code.api.OBPRestHelper
import code.util.Helper.MdcLoggable
import code.api.cache.Caching
import code.api.util.APIUtil._
import code.api.util.{APIUtil, ApiVersionUtils, YAMLUtils}
import code.api.v1_4_0.JSONFactory1_4_0
import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider
import code.util.Helper.{MdcLoggable, SILENCE_IS_GOLDEN}
import com.openbankproject.commons.model.enums.ContentParam.{DYNAMIC, STATIC}
import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus}
import net.liftweb.http.{GetRequest, InMemoryResponse, PlainTextResponse, Req, S}


object ResourceDocs140 extends OBPRestHelper with ResourceDocsAPIMethods with MdcLoggable {
Expand Down Expand Up @@ -152,6 +160,85 @@ object ResourceDocs300 extends OBPRestHelper with ResourceDocsAPIMethods with Md
route
})
})

// Register YAML endpoint using standard RestHelper approach
serve {
case Req("obp" :: versionStr :: "resource-docs" :: requestedApiVersionString :: "openapi.yaml" :: Nil, _, GetRequest) if versionStr == version.toString =>
val (resourceDocTags, partialFunctions, locale, contentParam, apiCollectionIdParam) = ResourceDocsAPIMethodsUtil.getParams()

// Validate parameters
if (S.param("tags").exists(_.trim.isEmpty)) {
PlainTextResponse("Invalid tags parameter - empty values not allowed", 400)
} else if (S.param("functions").exists(_.trim.isEmpty)) {
PlainTextResponse("Invalid functions parameter - empty values not allowed", 400)
} else if (S.param("api-collection-id").exists(_.trim.isEmpty)) {
PlainTextResponse("Invalid api-collection-id parameter - empty values not allowed", 400)
} else if (S.param("content").isDefined && contentParam.isEmpty) {
PlainTextResponse("Invalid content parameter. Valid values: static, dynamic, all", 400)
} else {
try {
val requestedApiVersion = ApiVersionUtils.valueOf(requestedApiVersionString)
if (!versionIsAllowed(requestedApiVersion)) {
PlainTextResponse(s"API Version not supported: $requestedApiVersionString", 400)
} else if (locale.isDefined && APIUtil.obpLocaleValidation(locale.get) != SILENCE_IS_GOLDEN) {
PlainTextResponse(s"Invalid locale: ${locale.get}", 400)
} else {
val isVersion4OrHigher = true
val cacheKey = APIUtil.createResourceDocCacheKey(
Some("openapi31yaml"),
requestedApiVersionString,
resourceDocTags,
partialFunctions,
locale,
contentParam,
apiCollectionIdParam,
Some(isVersion4OrHigher)
)
val cacheValueFromRedis = Caching.getStaticSwaggerDocCache(cacheKey)

val yamlString = if (cacheValueFromRedis.isDefined) {
cacheValueFromRedis.get
} else {
// Generate OpenAPI JSON and convert to YAML
val openApiJValue = try {
val resourceDocsJsonFiltered = locale match {
case _ if (apiCollectionIdParam.isDefined) =>
val operationIds = MappedApiCollectionEndpointsProvider.getApiCollectionEndpoints(apiCollectionIdParam.getOrElse("")).map(_.operationId).map(getObpFormatOperationId)
val resourceDocs = ResourceDoc.getResourceDocs(operationIds)
val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale)
resourceDocsJson.resource_docs
case _ =>
// Get all resource docs for the requested version
val allResourceDocs = ImplementationsResourceDocs.getResourceDocsList(requestedApiVersion).getOrElse(List.empty)
val filteredResourceDocs = ResourceDocsAPIMethodsUtil.filterResourceDocs(allResourceDocs, resourceDocTags, partialFunctions)
val resourceDocJson = JSONFactory1_4_0.createResourceDocsJson(filteredResourceDocs, isVersion4OrHigher, locale)
resourceDocJson.resource_docs
}

val hostname = HostName
val openApiDoc = code.api.ResourceDocs1_4_0.OpenAPI31JSONFactory.createOpenAPI31Json(resourceDocsJsonFiltered, requestedApiVersionString, hostname)
code.api.ResourceDocs1_4_0.OpenAPI31JSONFactory.OpenAPI31JsonFormats.toJValue(openApiDoc)
} catch {
case e: Exception =>
logger.error(s"Error generating OpenAPI JSON: ${e.getMessage}", e)
throw e
}

val yamlResult = YAMLUtils.jValueToYAMLSafe(openApiJValue, s"# Error converting OpenAPI to YAML: ${openApiJValue.toString}")
Caching.setStaticSwaggerDocCache(cacheKey, yamlResult)
yamlResult
}

val headers = List("Content-Type" -> YAMLUtils.getYAMLContentType)
val bytes = yamlString.getBytes("UTF-8")
InMemoryResponse(bytes, headers, Nil, 200)
}
} catch {
case _: Exception =>
PlainTextResponse(s"Invalid API version: $requestedApiVersionString", 400)
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import code.api.util.ExampleValue.endpointMappingRequestBodyExample
import code.api.util.FutureUtil.EndpointContext
import code.api.util.NewStyle.HttpCode
import code.api.util._
import code.api.util.YAMLUtils
import code.api.v1_4_0.JSONFactory1_4_0.ResourceDocsJson
import code.api.v1_4_0.{APIMethods140, JSONFactory1_4_0, OBPAPI1_4_0}
import code.api.v2_2_0.{APIMethods220, OBPAPI2_2_0}
Expand All @@ -32,7 +33,7 @@ import com.openbankproject.commons.model.{BankId, ListResult, User}
import com.openbankproject.commons.util.ApiStandards._
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
import net.liftweb.common.{Box, Empty, Full}
import net.liftweb.http.LiftRules
import net.liftweb.http.{InMemoryResponse, LiftRules, PlainTextResponse}
import net.liftweb.json
import net.liftweb.json.JsonAST.{JField, JString, JValue}
import net.liftweb.json._
Expand Down Expand Up @@ -769,6 +770,8 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
|
|This endpoint generates OpenAPI 3.1 compliant documentation with modern JSON Schema support.
|
|For YAML format, use the corresponding endpoint: /resource-docs/API_VERSION/openapi.yaml
|
|See the Resource Doc endpoint for more information.
|
|Note: Resource Docs are cached, TTL is ${GET_DYNAMIC_RESOURCE_DOCS_TTL} seconds
Expand Down Expand Up @@ -811,6 +814,11 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
List(apiTagDocumentation, apiTagApi)
)

// Note: OpenAPI 3.1 YAML endpoint (/resource-docs/API_VERSION/openapi.yaml)
// is implemented using Lift's serve mechanism in ResourceDocs140.scala to properly
// handle YAML content type. It provides the same functionality as the JSON endpoint
// but returns OpenAPI documentation in YAML format instead of JSON.

/**
* OpenAPI 3.1 endpoint with comprehensive parameter validation.
*
Expand Down Expand Up @@ -913,6 +921,25 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
}
}

// Note: The OpenAPI 3.1 YAML endpoint (/resource-docs/API_VERSION/openapi.yaml)
// is implemented using Lift's serve mechanism in ResourceDocs140.scala to properly
// handle YAML content type and response format, rather than as a standard OBPEndpoint.




def convertResourceDocsToOpenAPI31YAMLAndSetCache(cacheKey: String, requestedApiVersionString: String, resourceDocsJson: List[JSONFactory1_4_0.ResourceDocJson]) : String = {
logger.debug(s"Generating OpenAPI 3.1 YAML-convertResourceDocsToOpenAPI31YAMLAndSetCache requestedApiVersion is $requestedApiVersionString")
val hostname = HostName
val openApiDoc = code.api.ResourceDocs1_4_0.OpenAPI31JSONFactory.createOpenAPI31Json(resourceDocsJson, requestedApiVersionString, hostname)
val openApiJValue = code.api.ResourceDocs1_4_0.OpenAPI31JSONFactory.OpenAPI31JsonFormats.toJValue(openApiDoc)

val yamlString = YAMLUtils.jValueToYAMLSafe(openApiJValue, "# Error converting to YAML")
Caching.setStaticSwaggerDocCache(cacheKey, yamlString)

yamlString
}

private def convertResourceDocsToOpenAPI31JvalueAndSetCache(cacheKey: String, requestedApiVersionString: String, resourceDocsJson: List[JSONFactory1_4_0.ResourceDocJson]) : JValue = {
logger.debug(s"Generating OpenAPI 3.1-convertResourceDocsToOpenAPI31JvalueAndSetCache requestedApiVersion is $requestedApiVersionString")
val hostname = HostName
Expand Down
Loading