diff --git a/README.md b/README.md index 55685209e..a6150ca07 100644 --- a/README.md +++ b/README.md @@ -365,6 +365,9 @@ You can obfuscate passwords in the props file the same way as for jetty: ## Code Generation Please refer to the [Code Generation](https://github.com/OpenBankProject/OBP-API/blob/develop/CONTRIBUTING.md##code-generation) for links +## Customize Portal WebPage +Please refer to the [Custom Webapp](obp-api/src/main/resources/custom_webapp/README.md) for links + ## Using jetty password obfuscation with props file You can obfuscate passwords in the props file the same way as for jetty: diff --git a/obp-api/src/main/resources/custom_webapp/README.md b/obp-api/src/main/resources/custom_webapp/README.md new file mode 100644 index 000000000..74627eb71 --- /dev/null +++ b/obp-api/src/main/resources/custom_webapp/README.md @@ -0,0 +1,14 @@ +# custom_webapp folder + + +## Introduction + +This folder will contain the customer's front end files, it can not be tracked in the github. So the default is empty. + +If you set the props `use_custom_webapp=true`, that means you will use your own design of the frontend web page. + +Then you **MUST** copy all the files from the folder `OBP-API/obp-api/src/main/webapp` to here, and customize the HTML, CSS, +or JS files as your requirements. + + + diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index eb83c2418..191489e77 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -400,6 +400,9 @@ webui_oauth_2_documentation_url = oauth2_server_url = # Link to Privacy Policy on signup page +#webui_signup_form_title_text = Sign Up +#webui_signup_body_password_repeat_text = Repeat +#webui_agree_terms_html=
webui_agree_privacy_policy_url = https://openbankproject.com/privacy-policy webui_agree_privacy_policy_html_text =
@@ -470,6 +473,8 @@ webui_show_dummy_user_tokens=false webui_register_consumer_success_message_webpage = Thanks for registering your consumer with the Open Bank Project API! Here is your developer information. Please save it in a secure location. webui_register_consumer_success_message_email = Thank you for registering to use the Open Bank Project API. +#Log in page +#webui_login_button_text = ## End of webui_ section ######## diff --git a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala index 844960175..e8c28e289 100644 --- a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala +++ b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala @@ -29,6 +29,7 @@ package bootstrap.liftweb import java.io.{File, FileInputStream} import java.util.{Locale, TimeZone} +import org.apache.commons.io.FileUtils import code.CustomerDependants.MappedCustomerDependant import code.DynamicData.DynamicData import code.DynamicEndpoint.DynamicEndpoint @@ -243,7 +244,31 @@ class Boot extends MdcLoggable { import java.security.SecureRandom val rand = new SecureRandom(SecureRandom.getSeed(20)) rand - + + //If use_custom_webapp=true, this will copy all the files from `OBP-API/obp-api/src/main/webapp` to `OBP-API/obp-api/src/main/resources/custom_webapp` + if (APIUtil.getPropsAsBoolValue("use_custom_webapp", false)){ + //this `LiftRules.getResource` will get the path of `OBP-API/obp-api/src/main/webapp`: + LiftRules.getResource("/").map { url => + // this following will get the path of `OBP-API/obp-api/src/main/resources/custom_webapp` + val source = if (getClass().getClassLoader().getResource("custom_webapp") == null) + throw new RuntimeException("If you set `use_custom_webapp = true`, custom_webapp folder can not be Empty!!") + else + getClass().getClassLoader().getResource("custom_webapp").getPath + val srcDir = new File(source); + + // The destination directory to copy to. This directory + // doesn't exists and will be created during the copy + // directory process. + val destDir = new File(url.getPath) + + // Copy source directory into destination directory + // including its child directories and files. When + // the destination directory is not exists it will + // be created. This copy process also preserve the + // date information of the file. + FileUtils.copyDirectory(srcDir, destDir) + } + } // ensure our relational database's tables are created/fit the schema val connector = APIUtil.getPropsValue("connector").openOrThrowException("no connector set") diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala index fc77ff9b4..cc31e2259 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala @@ -89,7 +89,18 @@ class AuthUser extends MegaProtoUser[AuthUser] with MdcLoggable { override lazy val password = new MyPasswordNew + def signupPasswordRepeatText = getWebUiPropsValue("webui_signup_body_password_repeat_text", S.?("repeat")) + class MyPasswordNew extends MappedPassword(this) { + + override def _toForm: Box[NodeSeq] = { + S.fmapFunc({s: List[String] => this.setFromAny(s)}){funcName => + Full({appendFieldId()} {signupPasswordRepeatText} ) + } + } override def displayName = fieldOwner.passwordDisplayName @@ -409,12 +420,17 @@ import net.liftweb.util.Helpers._ } - def agreeTerms = { - val url = getWebUiPropsValue("webui_agree_terms_url", "") - if (url.isEmpty) { - s"" - } else { - scala.xml.Unparsed(s"""
""") + def agreeTermsDiv = { + val agreeTermsHtml = getWebUiPropsValue("webui_agree_terms_html", "") + if(agreeTermsHtml.isEmpty){ + val url = getWebUiPropsValue("webui_agree_terms_url", "") + if (url.isEmpty) { + s"" + } else { + scala.xml.Unparsed(s"""
""") + } + } else{ + scala.xml.Unparsed(s"""$agreeTermsHtml""") } } @@ -428,13 +444,15 @@ import net.liftweb.util.Helpers._ } } + def signupFormTitle = getWebUiPropsValue("webui_signup_form_title_text", S.?("sign.up")) + override def signupXhtml (user:AuthUser) = {
-

Sign Up

+

{signupFormTitle}

{localForm(user, false, signupFields)} - {agreeTerms} + {agreeTermsDiv} {agreePrivacyPolicy}
@@ -773,11 +791,13 @@ def restoreSomeSessions(): Unit = { } } + def loginButtonText = getWebUiPropsValue("webui_login_button_text", S.?("log.in")) + // In this function we bind submit button to loginAction function. // In case that unique token of submit button cannot be paired submit action will be omitted. // Implemented in order to prevent a CSRF attack def insertSubmitButton = { - scala.xml.XML.loadString(loginSubmitButton(S.?("Login"), loginAction _).toString().replace("type=\"submit\"","class=\"submit\" type=\"submit\"")) + scala.xml.XML.loadString(loginSubmitButton(loginButtonText, loginAction _).toString().replace("type=\"submit\"","class=\"submit\" type=\"submit\"")) } val bind = diff --git a/obp-api/src/main/scala/code/snippet/Login.scala b/obp-api/src/main/scala/code/snippet/Login.scala index 763add193..bf7784000 100644 --- a/obp-api/src/main/scala/code/snippet/Login.scala +++ b/obp-api/src/main/scala/code/snippet/Login.scala @@ -46,7 +46,7 @@ class Login { ".logout [href]" #> { AuthUser.logoutPath.foldLeft("")(_ + "/" + _) } & - ".logout #username *" #> AuthUser.getCurrentUserUsername + "#loggedIn-username *" #> AuthUser.getCurrentUserUsername } }