Merge branch 'develop' of github.com:OpenBankProject/OBP-API into develop

This commit is contained in:
Simon Redfern 2022-08-23 15:54:37 +02:00
commit 3fcda1e9c0
92 changed files with 2645 additions and 1124 deletions

View File

@ -21,8 +21,9 @@ jobs:
cache: maven
- name: Build with Maven
run: |
cp obp-api/src/main/resources/props/sample.props.template obp-api/src/main/resources/props/default.props
echo connector=star > obp-api/src/main/resources/props/test.default.props
echo starConnector_supported_types=mapped,internal > obp-api/src/main/resources/props/test.default.props
echo starConnector_supported_types=mapped,internal >> obp-api/src/main/resources/props/test.default.props
echo hostname=http://localhost:8016 >> obp-api/src/main/resources/props/test.default.props
echo tests.port=8016 >> obp-api/src/main/resources/props/test.default.props
echo End of minimum settings >> obp-api/src/main/resources/props/test.default.props

View File

@ -62,7 +62,12 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
<version>1.7.26</version>
</dependency>
<dependency>
<artifactId>slf4j-ext</artifactId>
<groupId>org.slf4j</groupId>
<version>1.7.26</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
@ -110,12 +115,12 @@
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>21.4.0.0</version>
<version>21.5.0.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.191</version>
<version>2.1.214</version>
<scope>runtime</scope>
</dependency>
<dependency>
@ -138,7 +143,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
@ -201,41 +206,27 @@
<artifactId>amqp_3.1_${scala.version}</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>com.tokbox</groupId>
<artifactId>opentok-server-sdk</artifactId>
<version>3.0.0-beta.2</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.tokbox</groupId>-->
<!-- <artifactId>opentok-server-sdk</artifactId>-->
<!-- <version>3.0.0-beta.2</version>-->
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>com.fasterxml.jackson.core</groupId>-->
<!-- <artifactId>jackson-databind</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
<!-- </dependency>-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.8.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sksamuel.elastic4s/elastic4s-client-esjava -->
<dependency>
<groupId>com.sksamuel.elastic4s</groupId>
<artifactId>elastic4s-http_${scala.version}</artifactId>
<version>6.1.1</version>
<!-- TODO try to switch to slf4j from log4j
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
</exclusion>
</exclusions> -->
<artifactId>elastic4s-client-esjava_${scala.version}</artifactId>
<version>8.2.1</version>
</dependency>
<!-- for LiftConsole -->
<dependency>
@ -356,10 +347,11 @@
<version>0.5.7</version>
</dependency>
<!-- embeded kafka for unit test start -->
<!-- https://mvnrepository.com/artifact/io.github.embeddedkafka/embedded-kafka -->
<dependency>
<groupId>net.manub</groupId>
<artifactId>scalatest-embedded-kafka_2.12</artifactId>
<version>2.0.0</version>
<groupId>io.github.embeddedkafka</groupId>
<artifactId>embedded-kafka_2.12</artifactId>
<version>2.4.1.1</version>
<scope>test</scope>
</dependency>
<!-- embeded kafka for unit test end -->
@ -444,7 +436,7 @@
<dependency>
<groupId>sh.ory.hydra</groupId>
<artifactId>hydra-client</artifactId>
<version>1.7.0</version>
<version>1.11.8</version>
</dependency>
<!--json schema validation start-->

View File

@ -1,84 +1,163 @@
api.explorer = Explorador API
introduction = Introducción
# The main drawback here is that all application resources for a given locale must exist
# in the same file, and that extended characters such as œ arent properly encoded by
# default. This is due to Java properties bundles using ISO 8859-1 encoding and thus
# requiring conversion to escaped format, such as \u0153. Fortunately this process can
# be automated using tools like native2ascii
# https://native2ascii.net/
# This tool will allow you to convert national language characters to and from their Unicode equivalents in plain ASCII text.
api.explorer = API Explorer
api_explorer = API Explorer
api_manager = Gestor API
introduction = Introducci\u00f3n
support = Soporte
register = Registrarse
logon = Ingresar
terms_conditions = Terminos y condiciones
privacy_policy = Pol\u00edtica de privacidad
api_documentation = Documentaci\u00f3n API
api_host = Host del API
api_tester = Evaluador API
view_api_explorer = Ver API Explorer
get_api_key = Obten llave API
welcome_to = Bienvenido a la instancia de prueba del API Sandbox del Open Bank Project!
get_started_building_your_application = Empiece a crear su aplicaci\ufffdn
for_banks = Para Bancos
invalid.email.address = Invalid email address
password.must.be.set = Password must be set
password.too.short = Password too short
passwords.do.not.match = Passwords do not match
number.required = A numeric value must be provided
ajax.error=The server cannot be contacted at this time
invalid.zip.code = Invalid ZIP code
invalid.postal.code = Invalid postal code
unique.email.address = The email address must be unique
must.be.logged.in = You must be logged in
already.logged.in = already logged in. Please logout first.
login = Login
logout = Logout
log.in = Log In
log.out = Log Out
sign.up = Sign Up
logged.in = Logged In
logout.first = Please logout first.
lost.password = Lost Password
reset.password = Reset Password
change.password = Change Password
password.changed = Password Changed
edit.user = Edit User
validate.user = Validate User
edit.profile = Edit Profile
sign.up.confirmation = Sign up confirmation
sign.up.message = You have signed up. A validation email message will be sent to you.
sign.up.validation.link=Click on this link to complete signup:
welcome = Welcome
account.validated = Account Validated
invalid.validation.link = Validation link invalid
account.validation.error = Your account has not been validated. Please check your email for a validation link.
invalid.credentials = Invalid Username/Password
enter.email = Enter your email address and we'll email you a link to reset your password
email.address = Email address
reset.password.confirmation = Reset Password Confirmation
dear = Dear
click.reset.link = Click on this link to reset your password
thank.you = Thank you
reset.password.request = Reset Password Request
password.reset.email.sent = Password Reset Email sent
account.validation.resent = Account Validation Re-sent
email.address.not.found = Email address not found
send.it = Send It
reset.your.password = Reset your password
enter.your.new.password = Enter your new password
repeat.your.new.password = Enter your new password (repeat)
set.password = Set Password
password.link.invalid = Password reset link invalid
wrong.old.password = Wrong old password
old.password = Old password
new.password = New password
repeat.password = New password (repeat)
repeat = Repeat
edit = Edit
Get_started = Empezar
Create_an_account = Crea una cuenta
Description_Create_an_account = En primer lugar, crea una cuenta de desarrollador gratuita en este sandbox y solicita una clave de desarrollador. En esta fase se te pedir\ufffd que env\ufffdes informaci\ufffdn b\ufffdsica sobre tu aplicaci\ufffdn.
Connect_your_app = Conecta tu app
Connect_your_app_description = Utiliza nuestros SDKs para conectar tu aplicaci\ufffdn a las APIs de Open Bank Project. Necesitar\ufffds tu clave de desarrollador, que deber\ufffdas tener desde que creaste tu cuenta. Consulta todas las APIs disponibles en el Explorador de APIs, pero aseg\ufffdrate de que est\ufffds utilizando la URL base correcta.
Test_your_app = Pruebe su aplicaci\ufffdn con datos de clientes
Test_your_app_description = una vez que su aplicaci\ufffdn est\ufffd conectada, puede probarla utilizando las credenciales del cliente de prueba.
register_for_an_account = Registrar una cuenta nueva
# Explore APIs Section
explore_api_title = Explorar los titulos de las API
explore_api_accounts_title = Cuentas
explore_api_accounts = Acceso a cuentas (XS21) y tarjetas. Proporcionar acceso de grano fino a los invitados (auditor, contable o p\ufffdblico).
explore_api_branches_title = Sucursales, cajeros y productos
explore_api_branches = Acceda a los datos abiertos relacionados con los bancos, incluidas las sucursales y los cajeros autom\ufffdticos, as\ufffd como la geolocalizaci\ufffdn y los horarios de apertura.
explore_api_transactions_title = Transacciones
explore_api_transactions = Acceda al historial de transacciones y a los metadatos de las mismas.
explore_api_metadata_title = Metadata
explore_api_metadata = Enriquezca las transacciones y las contrapartes con metadatos que incluyan geolocalizaciones, comentarios, im\ufffdgenes y etiquetas (por ejemplo, categor\ufffda de gasto).
explore_api_counterparties_title = Metadata
explore_api_counterparties = Acceda a los pagadores y beneficiarios de una cuenta, incluyendo metadatos como sus alias, etiquetas, logotipos y p\ufffdginas de inicio.
explore_api_webhooks_title = Webhooks
explore_api_webhooks = Llamar a servicios web externos basados en eventos de la Cuenta.
explore_api_customer_title = Incorporaci\ufffdn de clientes y KYC
explore_api_customer = Realizar la creaci\ufffdn de usuarios, clientes y cuentas. Gestionar los documentos, los medios y el estado de Conozca a su Cliente (KYC). Crear reuniones y mensajes de clientes.
explore_api_roles_title = Funciones, m\ufffdtricas y documentaci\ufffdn de la API
explore_api_roles = Controle el acceso a los puntos finales, obtenga m\ufffdtricas y documentaci\ufffdn de la API.
explore_api_payments_title = Pagos y transferencias
explore_api_payments = Iniciar solicitudes de transacciones (transferencias y pagos). Ver y confirmar cargos (seg\ufffdn la PSD2). Responder a los retos de autenticaci\ufffdn fuerte del cliente (SCA).
explore_api_warehouse_title = Buscar en el almac\ufffdn
explore_api_warehouse = Realice b\ufffdsquedas avanzadas y consultas estad\ufffdsticas en el almac\ufffdn de datos.
# Get Started Section
get_started_title = Empezar
get_started_create_account_title = Crea una cuenta
get_started_create_account = En primer lugar, crea una cuenta de desarrollador gratuita en este sandbox y solicita una clave de desarrollador. En esta fase se te pedir\u00e1 que env\u00edes informaci\u00f3n b\u00e1sica sobre tu aplicaci\u00f3n.
get_started_create_account_sign_up = Register for an account
get_started_connect_your_app_title = Conecta tu app
get_started_connect_your_app = Utiliza nuestros SDKs para conectar tu aplicaci\u00f3n a las APIs de Open Bank Project. Necesitar\u00e1s tu clave de desarrollador, que deber\u00edas tener desde que creaste tu cuenta. Consulta todas las APIs disponibles en el Explorador de APIs, pero aseg\u00farate de que est\u00e1s utilizando la URL base correcta.
get_started_test_your_app_title = Pruebe su aplicaci\u00f3n con datos de clientes
get_started_test_your_app = Una vez que su aplicaci\u00f3n est\u00e9 conectada, puede probarla utilizando las credenciales del cliente de prueba.
get_started_test_your_app_sandbox_date = View sandbox customer log ons.
username = Nombre de usuario
logontext = Acceda a la API del Open Bank Project
passwordlog = Contrase\ufffda
Forgotten_password = \ufffdHas olvidado tu contrase\ufffda?
don't_have_account = \ufffdNo Tienes una cuenta?
or_login_with_openid = o con\ufffdctate con OpenID
or = o
invalid.email.address = Direcci\ufffdn de correo electr\ufffdnico no v\ufffdlida
password.must.be.set = Hay que poner la contrase\ufffda
password.too.short = Contrase\ufffda demasiado corta
passwords.do.not.match = Las contrase\ufffdas no coinciden
number.required = Se debe proporcionar un valor num\ufffdrico
ajax.error=El servidor no puede ser contactado en este momento
invalid.zip.code = C\ufffddigo postal inv\ufffdlido
invalid.postal.code = C\ufffddigo postal inv\ufffdlido
unique.email.address = La direcci\ufffdn de correo electr\ufffdnico debe ser \ufffdnica
must.be.logged.in = Debe estar conectado
already.logged.in = ya ha iniciado la sesi\ufffdn. Por favor, cierre la sesi\ufffdn primero.
login = Ingresar
logout = Salir
log.in = Ingresar
log.out = Salir
sign.up = Registrarse
logged.in = Ingresar
logout.first = Por favor, cierre la sesi\ufffdn primero.
lost.password = Contrase\ufffda perdida
reset.password = Restablecer contrase\ufffda
change.password = Cambiar la contrase\ufffda
password.changed = Contrase\ufffda cambiada
edit.user = Editar usuario
validate.user = Validar usuario
edit.profile = Editar perfil
sign.up.confirmation = Confirmaci\ufffdn de inscripci\ufffdn
sign.up.message = Se ha inscrito. Se le enviar\ufffd un mensaje de correo electr\ufffdnico de validaci\ufffdn.
sign.up.validation.link=Haga clic en este enlace para completar la inscripci\ufffdn:
welcome = Bienvenido
account.validated = Cuenta validada
invalid.validation.link = Enlace de validaci\ufffdn inv\ufffdlido
account.validation.error = Su cuenta no ha sido validada. Por favor, compruebe su correo electr\ufffdnico para un enlace de validaci\ufffdn.
invalid.credentials = Nombre de usuario/contrase\ufffda no v\ufffdlidos
enter.email = Introduzca su direcci\ufffdn de correo electr\ufffdnico y le enviaremos un enlace para restablecer su contrase\ufffda
email.address = Correo electr\ufffdnico
reset.password.confirmation = Confirmacion para reestablecer la contrase\ufffda
dear = Apreciable
click.reset.link = Da click en el enlace para reestablecer tu contrase\ufffda
thank.you = Gracias
reset.password.request = Solicitud para reestablecer contrase\ufffda
password.reset.email.sent = Contrase\ufffda para reestablecer el correo ha sido enviada
account.validation.resent = Validaci\ufffdn de la cuenta enviado de nuevo
email.address.not.found = Direcci\ufffdn de correo no encontrado
send.it = Enviar
reset.your.password = Resetea tu contrase\ufffda
enter.your.new.password = Escribe tu contrase\ufffda
repeat.your.new.password = Escribe tu contrase\ufffda (repitela)
set.password = Establecer contrase\ufffda
password.link.invalid = Enlace para cambio de contrase\ufffda invalido
wrong.old.password = Contrase\ufffda equivocada
old.password = Contrase\ufffda antigua
new.password = Nueva contrase\ufffda
repeat.password = Nueva contrase\ufffda (repetir)
repeat = Repetir
edit = Editar
cancel = Cancel
ok = OK
change = Change
password = Password
recover.password = Recover Password
profile.updated = You have updated your profile
male = Male
female = Female
first.name = First name
last.name = Last name
locale = Locale
time.zone = Time Zone
msg.notice = Notice
msg.warning = Warning
change = Cambiar
password = Contrase\ufffda
recover.password = Recuperar contrase\ufffda
profile.updated = Has actualizado tu perfil
male = Masculino
female = Femenino
first.name = Primer Nombre
last.name = Apellido
locale = Localidad
time.zone = Zona Horaria
msg.notice = Advertencia
msg.warning = Peligro
msg.error = Error
crudify.menu.view.displayName=View %s
crudify.menu.edit.displayName=Edit %s
crudify.menu.delete.displayName=Delete %s
paginator.norecords = There are no records to display
paginator.displayingrecords = Displaying %s-%s of %s
crudify.menu.view.displayName=Ver %s
crudify.menu.edit.displayName=Editar %s
crudify.menu.delete.displayName=Borrar %s
paginator.norecords = No hay informaci\ufffdn que mostrar
paginator.displayingrecords = Mostrando %s-%s de %s
open_bank_project_is = Open Bank Project es
and_commercial_licenses = TESOBE y licencias comerciales
# Country names
country_1 = United States
country_2 = Afghanistan
@ -353,35 +432,37 @@ country_270 = Peter I Island
country_271 = Queen Maud Land
country_272 = British Antarctic Territory
# LiftScreen + Wizard
Next = Next
Previous = Previous
Finish = Finish
Cancel = Cancel
Next = Siguiente
Previous = Anterior
Finish = Terminado
Cancel = Cancelado
# Crudify
Create = Create
Save = Save
Edit = Edit
Delete = Delete
delete = delete
View = View
List = List %s
Created = Created
Edited = Edited
Deleted = Deleted
Create = Crear
Save = Guardar
Edit = Editar
Delete = Borrar
delete = borrar
View = Ver
List = lista %s
Created = Creado
Edited = Editado
Deleted = Borrado
#OBP specific fields
consumer.registration.nav.name=Obtener llave API
invalid.login.credentials=Invalid Login Credentials
invalid.username=Invalid Username: \
1) The ONLY allowed characters in Usernames are: a-z A-Z 0-9 . _ \
2) Usernames MUST be between 8 and 100 characters long \
3) Usernames MUST NOT start with _ or . \
4) Usernames MUST NOT contain __ or ._ or ._ or .. \
5) Usernames MUST NOT end with _ or . \
6) Any valid email address is allowed as the Username
invalid.login.credentials= Credenciales invalidas
invalid.username=Nombre de usuario invalido: \
1) Los \ufffdnicos caracteres permitidos en los nombres de usuario son: a-z A-Z 0-9 . _ \
2) Los nombres de usuario DEBEN tener entre 8 y 100 caracteres \
3) Los nombres de usuario NO DEBEN empezar por _ o . \
4) Los nombres de usuario NO DEBEN contener __ o ._ o ._ o .. \
5) Los nombres de usuario NO DEBEN terminar con _ o . \
6) Cualquier direcci\ufffdn de correo electr\ufffdnico v\ufffdlida est\ufffd permitida como nombre de usuario
your.username.is.not.unique = Your username is not unique. Please enter a different one.
your.username.is.not.unique = Su nombre de usuario no es \ufffdnico. Por favor, introduzca uno diferente.
# Those 2 messages must have the same output in order to prevent leakage of information
user.invitation.is.already.finished = Looks like the invitation link is invalid. Still need help? Please send us a message using API Playground Support.
your.secret.link.is.not.valid = Looks like the invitation link is invalid. Still need help? Please send us a message using API Playground Support.
user.invitation.is.already.finished = Parece que el enlace de invitaci\ufffdn no es v\ufffdlido. \ufffdTodav\ufffda necesitas ayuda? Por favor, env\ufffdanos un mensaje usando el soporte de API Playground.
your.secret.link.is.not.valid = Parece que el enlace de invitaci\ufffdn no es v\ufffdlido. \ufffdTodav\ufffda necesitas ayuda? Por favor, env\ufffdanos un mensaje usando el soporte de API Playground.
OBP-30001 = El usuario no ha iniciado sesi\u00c3\u00b3n. \u00c2\u00a1Se requiere autenticaci\u00c3\u00b3n!

View File

@ -0,0 +1,347 @@
invalid.email.address = \u65e0\u6548\u7535\u5b50\u90ae\u7bb1\u5730\u5740
password.must.be.set = \u5bc6\u7801\u4e0d\u80fd\u4e3a\u7a7a
password.too.short = \u5bc6\u7801\u592a\u77ed
passwords.do.not.match = \u5bc6\u7801\u4e0d\u5339\u914d
number.required = \u53ea\u80fd\u63d0\u4f9b\u6570\u5b57\u503c
ajax.error=\u8fde\u63a5\u670d\u52a1\u5668\u5931\u8d25
invalid.zip.code = \u65e0\u6548\u90ae\u653f\u7f16\u7801
invalid.postal.code = \u65e0\u6548\u90ae\u653f\u7f16\u7801
unique.email.address = \u7535\u5b50\u90ae\u7bb1\u5730\u5740\u5df2\u5b58\u5728
must.be.logged.in = \u8bf7\u5148\u767b\u5f55
already.logged.in = \u5df2\u7ecf\u767b\u5f55\uff0c\u8bf7\u5148\u767b\u51fa
login = \u767b\u5f55
logout = \u767b\u51fa
log.in = \u767b\u5f55
log.out = \u767b\u51fa
sign.up = \u6ce8\u518c
logged.in = \u5df2\u767b\u5f55
logout.first = \u8bf7\u5148\u767b\u51fa
lost.password = \u5fd8\u8bb0\u5bc6\u7801
reset.password = \u91cd\u7f6e\u5bc6\u7801
change.password = \u4fee\u6539\u5bc6\u7801
password.changed = \u5bc6\u7801\u5df2\u4fee\u6539
edit.user = \u8bbe\u7f6e\u7528\u6237
validate.user = \u6821\u9a8c\u7528\u6237
edit.profile = \u4fee\u6539\u8d44\u6599
sign.up.confirmation = \u6ce8\u518c\u4fe1\u606f\u786e\u8ba4
sign.up.message = \u6ce8\u518c\u6210\u529f\uff0c\u7cfb\u7edf\u4f1a\u53d1\u9001\u4e00\u5c01\u5e10\u53f7\u9a8c\u8bc1\u90ae\u4ef6\u5230\u4f60\u7684\u7535\u5b50\u90ae\u7bb1
sign.up.validation.link=\u70b9\u51fb\u6b64\u94fe\u63a5\u5b8c\u6210\u6ce8\u518c\uff1a
welcome = \u6b22\u8fce
account.validated = \u5e10\u53f7\u9a8c\u8bc1\u6210\u529f
invalid.validation.link = \u9a8c\u8bc1\u94fe\u63a5\u65e0\u6548
account.validation.error = \u60a8\u7684\u5e10\u53f7\u8fd8\u6ca1\u9a8c\u8bc1\uff0c\u8bf7\u68c0\u67e5\u60a8\u7684\u90ae\u7bb1\u83b7\u5f97\u9a8c\u8bc1\u94fe\u63a5
invalid.credentials = \u7528\u6237\u540d/\u5bc6\u7801\u9519\u8bef
enter.email = \u8f93\u5165\u4e00\u4e2a\u7535\u5b50\u90ae\u7bb1\u5730\u5740\uff0c\u6211\u4eec\u4f1a\u53d1\u9001\u4e00\u4e2a\u5bc6\u7801\u91cd\u7f6e\u94fe\u63a5\u5230\u8be5\u90ae\u7bb1
email.address = \u7535\u5b50\u90ae\u7bb1\u5730\u5740
reset.password.confirmation = \u91cd\u7f6e\u5bc6\u7801\u4fe1\u606f\u786e\u8ba4
dear = \u5c0a\u656c\u7684
click.reset.link = \u70b9\u51fb\u6b64\u94fe\u63a5\u91cd\u7f6e\u60a8\u7684\u5bc6\u7801
thank.you = \u8c22\u8c22
reset.password.request = \u8bf7\u6c42\u5bc6\u7801\u91cd\u7f6e
password.reset.email.sent = \u5bc6\u7801\u91cd\u7f6e\u90ae\u4ef6\u5df2\u53d1\u9001
account.validation.resent = \u91cd\u53d1\u5e10\u53f7\u9a8c\u8bc1\u90ae\u4ef6
email.address.not.found = \u7535\u5b50\u90ae\u7bb1\u5730\u5740\u4e0d\u5b58\u5728
send.it = \u53d1\u9001
reset.your.password = \u91cd\u7f6e\u5bc6\u7801
enter.your.new.password = \u8f93\u5165\u65b0\u5bc6\u7801
repeat.your.new.password = \u8f93\u5165\u65b0\u5bc6\u7801\uff08\u786e\u8ba4\uff09
set.password = \u8bbe\u7f6e\u5bc6\u7801
password.link.invalid = \u5bc6\u7801\u91cd\u7f6e\u94fe\u7ed3\u65e0\u6548
wrong.old.password = \u539f\u5bc6\u7801\u9519\u8bef
old.password = \u539f\u5bc6\u7801
new.password = \u65b0\u5bc6\u7801
repeat.password = \u65b0\u5bc6\u7801\u786e\u8ba4
repeat = \u786e\u8ba4
edit = \u4fee\u6539
cancel = \u53d6\u6d88
ok = \u786e\u5b9a
change = \u4fee\u6539
password = \u5bc6\u7801
recover.password = \u6062\u590d\u5bc6\u7801
profile.updated = \u60a8\u7684\u8d44\u6599\u4fee\u6539\u6210\u529f
male = \u7537
female = \u5973
first.name = \u540d
last.name = \u59d3
locale = \u533a\u57df
time.zone = \u65f6\u533a
msg.notice = \u4fe1\u606f
msg.warning = \u8b66\u544a
msg.error = \u9519\u8bef
crudify.menu.view.displayName=\u67e5\u770b %s
crudify.menu.edit.displayName=\u8bbe\u7f6e %s
crudify.menu.delete.displayName=\u5220\u9664 %s
country_1 = \u7f8e\u56fd
country_2 = \u963f\u5bcc\u6c57
country_3 = \u963f\u5c14\u5df4\u5c3c\u4e9a
country_4 = \u963f\u5c14\u53ca\u5229\u4e9a
country_5 = \u5b89\u9053\u5c14
country_6 = \u5b89\u54e5\u62c9
country_7 = \u5b89\u63d0\u74dc\u548c\u5df4\u5e03\u8fbe
country_8 = \u963f\u6839\u5ef7
country_9 = \u4e9a\u7f8e\u5c3c\u4e9a
country_10 = \u6fb3\u5927\u5229\u4e9a
country_11 = \u5965\u5730\u5229
country_12 = \u963f\u585e\u62dc\u7586
country_13 = \u5df4\u54c8\u9a6c
country_14 = \u5df4\u6797
country_15 = \u5b5f\u52a0\u62c9\u56fd
country_16 = \u5df4\u5df4\u591a\u65af
country_17 = \u767d\u4fc4\u7f57\u65af
country_18 = \u6bd4\u5229\u65f6
country_19 = \u4f2f\u5229\u5179
country_20 = \u8d1d\u5b81
country_21 = \u4e0d\u4e39
country_22 = \u73bb\u5229\u7ef4\u4e9a
country_23 = \u6ce2\u65af\u5c3c\u4e9a\u548c\u9ed1\u585e\u54e5\u7ef4
country_24 = \u535a\u8328\u74e6\u7eb3
country_25 = \u5df4\u897f
country_26 = \u6587\u83b1
country_27 = \u4fdd\u52a0\u5229\u4e9a
country_28 = \u5e03\u57fa\u7eb3\u6cd5\u7d22
country_29 = \u5e03\u9686\u8fea
country_30 = \u67ec\u57d4\u5be8
country_31 = \u5580\u9ea6\u9686
country_32 = \u52a0\u62ff\u5927
country_33 = \u4f5b\u5f97\u89d2
country_34 = \u4e2d\u975e\u5171\u548c\u56fd
country_35 = \u4e4d\u5f97
country_36 = \u667a\u5229
country_37 = \u4e2d\u56fd
country_38 = \u54e5\u4f26\u6bd4\u4e9a
country_39 = \u79d1\u6469\u7f57
country_40 = \u521a\u679c\u6c11\u4e3b\u5171\u548c\u56fd
country_41 = \u521a\u679c\u5171\u548c\u56fd
country_42 = \u54e5\u65af\u8fbe\u9ece\u52a0
country_43 = \u79d1\u7279\u8fea\u74e6
country_44 = \u514b\u7f57\u5730\u4e9a
country_45 = \u53e4\u5df4
country_46 = \u585e\u6d66\u8def\u65af
country_47 = \u6377\u514b\u5171\u548c\u56fd
country_48 = \u4e39\u9ea6
country_49 = \u5409\u5e03\u63d0
country_50 = \u591a\u7c73\u5c3c\u52a0
country_51 = \u591a\u7c73\u5c3c\u52a0\u5171\u548c\u56fd
country_52 = \u5384\u74dc\u591a\u5c14
country_53 = \u57c3\u53ca
country_54 = \u8428\u5c14\u74e6\u591a
country_55 = \u8d64\u9053\u51e0\u5185\u4e9a
country_56 = \u5384\u7acb\u7279\u91cc\u4e9a
country_57 = \u7231\u6c99\u5c3c\u4e9a
country_58 = \u57c3\u585e\u4fc4\u6bd4\u4e9a
country_59 = \u6590\u6d4e
country_60 = \u82ac\u5170
country_61 = \u6cd5\u56fd
country_62 = \u52a0\u84ec
country_63 = \u5188\u6bd4\u4e9a\uff0c
country_64 = \u683c\u9c81\u5409\u4e9a
country_65 = \u5fb7\u56fd
country_66 = \u52a0\u7eb3
country_67 = \u5e0c\u814a
country_68 = \u683c\u6797\u7eb3\u8fbe
country_69 = \u5371\u5730\u9a6c\u62c9
country_70 = \u51e0\u5185\u4e9a
country_71 = \u51e0\u5185\u4e9a\u6bd4\u7ecd
country_72 = \u572d\u4e9a\u90a3
country_73 = \u6d77\u5730
country_74 = \u6d2a\u90fd\u62c9\u65af
country_75 = \u5308\u7259\u5229
country_76 = \u51b0\u5c9b
country_77 = \u5370\u5ea6
country_78 = \u5370\u5ea6\u5c3c\u897f\u4e9a
country_79 = \u4f0a\u6717
country_80 = \u4f0a\u62c9\u514b
country_81 = \u7231\u5c14\u5170
country_82 = \u4ee5\u8272\u5217
country_83 = \u610f\u5927\u5229
country_84 = \u7259\u4e70\u52a0
country_85 = \u65e5\u672c
country_86 = \u7ea6\u65e6
country_87 = \u54c8\u8428\u514b\u65af\u5766
country_88 = \u80af\u5c3c\u4e9a
country_89 = \u57fa\u91cc\u5df4\u65af
country_90 = \u671d\u9c9c
country_91 = \u97e9\u56fd
country_92 = \u79d1\u5a01\u7279
country_93 = \u5409\u5c14\u5409\u65af\u65af\u5766
country_94 = \u8001\u631d
country_95 = \u62c9\u8131\u7ef4\u4e9a
country_96 = \u9ece\u5df4\u5ae9
country_97 = \u83b1\u7d22\u6258
country_98 = \u5229\u6bd4\u91cc\u4e9a
country_99 = \u5229\u6bd4\u4e9a
country_100 = \u5217\u652f\u6566\u58eb\u767b
country_101 = \u7acb\u9676\u5b9b
country_102 = \u5362\u68ee\u5821
country_103 = \u9a6c\u5176\u987f
country_104 = \u9a6c\u8fbe\u52a0\u65af\u52a0
country_105 = \u9a6c\u62c9\u7ef4
country_106 = \u9a6c\u6765\u897f\u4e9a
country_107 = \u9a6c\u5c14\u4ee3\u592b
country_108 = \u9a6c\u91cc
country_109 = \u9a6c\u8033\u4ed6
country_110 = \u9a6c\u7ecd\u5c14\u7fa4\u5c9b
country_111 = \u6bdb\u91cc\u5854\u5c3c\u4e9a
country_112 = \u6bdb\u91cc\u6c42\u65af
country_113 = \u58a8\u897f\u54e5
country_114 = \u5bc6\u514b\u7f57\u5c3c\u897f\u4e9a
country_115 = \u6469\u5c14\u591a\u74e6
country_116 = \u6469\u7eb3\u54e5
country_117 = \u8499\u53e4
country_118 = \u9ed1\u5c71
country_119 = \u6469\u6d1b\u54e5
country_120 = \u83ab\u6851\u6bd4\u514b
country_121 = \u7f05\u7538
country_122 = \u7eb3\u7c73\u6bd4\u4e9a
country_123 = \u7459\u9c81
country_124 = \u5c3c\u6cca\u5c14
country_125 = \u8377\u5170
country_126 = \u65b0\u897f\u5170
country_127 = \u5c3c\u52a0\u62c9\u74dc
country_128 = \u5c3c\u65e5\u5c14
country_129 = \u5c3c\u65e5\u5229\u4e9a
country_130 = \u632a\u5a01
country_131 = \u963f\u66fc
country_132 = \u5df4\u57fa\u65af\u5766
country_133 = \u5e15\u52b3
country_134 = \u5df4\u62ff\u9a6c
country_135 = \u5df4\u5e03\u4e9a\u65b0\u51e0\u5185\u4e9a
country_136 = \u5df4\u62c9\u572d
country_137 = \u79d8\u9c81
country_138 = \u83f2\u5f8b\u5bbe
country_139 = \u6ce2\u5170
country_140 = \u8461\u8404\u7259
country_141 = \u5361\u5854\u5c14
country_142 = \u7f57\u9a6c\u5c3c\u4e9a
country_143 = \u4fc4\u7f57\u65af
country_144 = \u5362\u65fa\u8fbe
country_145 = \u5723\u57fa\u8328\u548c\u5c3c\u7ef4\u65af
country_146 = \u5723\u5362\u897f\u4e9a
country_147 = \u5723\u6587\u68ee\u7279\u548c\u683c\u6797\u7eb3\u4e01\u65af
country_148 = \u8428\u6469\u4e9a
country_149 = \u5723\u9a6c\u529b\u8bfa
country_150 = \u5723\u591a\u7f8e\u548c\u666e\u6797\u897f\u6bd4
country_151 = \u6c99\u7279\u963f\u62c9\u4f2f
country_152 = \u585e\u5185\u52a0\u5c14
country_153 = \u585e\u5c14\u7ef4\u4e9a
country_154 = \u585e\u820c\u5c14
country_155 = \u585e\u62c9\u5229\u6602
country_156 = \u65b0\u52a0\u5761
country_157 = \u65af\u6d1b\u4f10\u514b
country_158 = \u65af\u6d1b\u6587\u5c3c\u4e9a
country_159 = \u6240\u7f57\u95e8\u7fa4\u5c9b
country_160 = \u7d22\u9a6c\u91cc
country_161 = \u5357\u975e
country_162 = \u897f\u73ed\u7259
country_163 = \u65af\u91cc\u5170\u5361
country_164 = \u82cf\u4e39
country_165 = \u82cf\u91cc\u5357
country_166 = \u65af\u5a01\u58eb\u5170
country_167 = \u745e\u5178
country_168 = \u745e\u58eb
country_169 = \u53d9\u5229\u4e9a
country_170 = \u5854\u5409\u514b\u65af\u5766
country_171 = \u5766\u6851\u5c3c\u4e9a
country_172 = \u6cf0\u56fd
country_173 = \u4e1c\u5e1d\u6c76
country_174 = \u591a\u54e5
country_175 = \u6c64\u52a0
country_176 = \u7279\u7acb\u5c3c\u8fbe\u548c\u591a\u5df4\u54e5
country_177 = \u7a81\u5c3c\u65af
country_178 = \u571f\u8033\u5176
country_179 = \u571f\u5e93\u66fc\u65af\u5766
country_180 = \u56fe\u74e6\u5362
country_181 = \u4e4c\u5e72\u8fbe
country_182 = \u4e4c\u514b\u5170
country_183 = \u963f\u62c9\u4f2f\u8054\u5408\u914b\u957f\u56fd
country_184 = \u82f1\u56fd
country_185 = \u4e4c\u62c9\u572d
country_186 = \u4e4c\u5179\u522b\u514b\u65af\u5766
country_187 = \u74e6\u52aa\u963f\u56fe
country_188 = \u68b5\u8482\u5188\u57ce
country_189 = \u59d4\u5185\u745e\u62c9
country_190 = \u8d8a\u5357
country_191 = \u4e5f\u95e8
country_192 = \u8d5e\u6bd4\u4e9a
country_193 = \u6d25\u5df4\u5e03\u97e6
country_194 = \u963f\u5e03\u54c8\u5179
country_195 = \u53f0\u6e7e
country_196 = \u7eb3\u5361
country_197 = \u5317\u585e\u6d66\u8def\u65af
country_198 = \u5fb7\u6d85\u65af\u7279\u6cb3\u6cbf\u5cb8\u5171\u548c\u56fd
country_199 = \u7d22\u9a6c\u91cc\u5170
country_200 = \u5357\u5965\u585e\u68af
country_201 = \u963f\u4ec0\u83ab\u5c14\u548c\u5361\u6377\u5c9b
country_202 = \u5723\u8bde\u5c9b
country_203 = \u79d1\u79d1\u65af\uff08\u57fa\u6797\uff09\u7fa4\u5c9b
country_204 = \u73ca\u745a\u6d77\u7fa4\u5c9b
country_205 = \u8d6b\u5fb7\u5c9b\u548c\u9ea6\u5f53\u52b3\u7fa4\u5c9b
country_206 = \u8bfa\u798f\u514b\u5c9b
country_207 = \u65b0\u5580\u91cc\u591a\u5c3c\u4e9a
country_208 = \u6cd5\u5c5e\u6ce2\u5229\u5c3c\u897f\u4e9a
country_209 = \u9a6c\u7ea6\u7279
country_210 = \u5723\u5df4\u6cf0\u52d2\u7c73
country_211 = \u5723\u9a6c\u4e01
country_212 = \u5723\u76ae\u57c3\u5c14\u548c\u5bc6\u514b\u9686
country_213 = \u74e6\u5229\u65af\u7fa4\u5c9b\u548c\u5bcc\u56fe\u7eb3\u7fa4\u5c9b
country_214 = \u6cd5\u56fd\u5357\u90e8\u548c\u5357\u6781\u9886\u5730
country_215 = \u514b\u5229\u73c0\u987f\u5c9b
country_216 = \u5e03\u7ef4\u5c9b
country_217 = \u5e93\u514b\u7fa4\u5c9b
country_218 = \u7ebd\u57c3
country_219 = \u6258\u514b\u52b3
country_220 = \u6839\u897f\u5c9b
country_221 = \u9a6c\u6069\u5c9b
country_222 = \u6cfd\u897f
country_223 = \u5b89\u572d\u62c9
country_224 = \u767e\u6155\u5927
country_225 = \u82f1\u5c5e\u5370\u5ea6\u6d0b\u9886\u5730
country_226 = \u82f1\u56fd\u4e3b\u6743\u57fa\u5730\u533a
country_227 = \u82f1\u5c5e\u7ef4\u5c14\u4eac\u7fa4\u5c9b
country_228 = \u5f00\u66fc\u7fa4\u5c9b
country_229 = \u798f\u514b\u5170\u7fa4\u5c9b
country_230 = \u76f4\u5e03\u7f57\u9640
country_231 = \u8499\u7279\u585e\u62c9\u7279
country_232 = \u76ae\u7279\u51ef\u6069\u7fa4\u5c9b
country_233 = \u5723\u6d77\u4f26\u5a1c
country_234 = \u5357\u4e54\u6cbb\u4e9a\u5c9b\u548c\u5357\u6851\u5a01\u5947\u7fa4\u5c9b
country_235 = \u7279\u514b\u65af\u548c\u51ef\u79d1\u65af\u7fa4\u5c9b
country_236 = \u5317\u9a6c\u91cc\u4e9a\u7eb3\u7fa4\u5c9b
country_237 = \u6ce2\u591a\u9ece\u5404
country_238 = \u7f8e\u5c5e\u8428\u6469\u4e9a
country_239 = \u8d1d\u514b\u5c9b
country_240 = \u5173\u5c9b
country_241 = \u8c6a\u5170\u5c9b
country_242 = \u8d3e\u7ef4\u65af\u5c9b
country_243 = \u7ea6\u7ff0\u65af\u987f\u73af\u7901
country_244 = \u91d1\u66fc\u7901
country_245 = \u4e2d\u9014\u5c9b
country_246 = \u7eb3\u74e6\u8428\u5c9b
country_247 = \u5df4\u5c14\u7c73\u62c9\u73af\u7901
country_248 = \u7f8e\u56fd\u7ef4\u5c14\u4eac\u7fa4\u5c9b
country_249 = \u5a01\u514b\u5c9b
country_250 = \u9999\u6e2f
country_251 = \u6fb3\u95e8
country_252 = \u6cd5\u7f57\u7fa4\u5c9b
country_253 = \u683c\u9675\u5170
country_254 = \u6cd5\u5c5e\u572d\u4e9a\u90a3
country_255 = \u74dc\u5fb7\u7f57\u666e\u5c9b
country_256 = \u9a6c\u63d0\u5c3c\u514b
country_257 = \u7559\u5c3c\u6c6a
country_258 = \u5965\u5170
country_259 = \u963f\u9c81\u5df4
country_260 = \u8377\u5c5e\u5b89\u7684\u5217\u65af
country_261 = \u65af\u74e6\u5c14\u5df4\u5fb7
country_262 = \u963f\u68ee\u677e
country_263 = \u7279\u91cc\u65af\u5766\u8fbe\u5e93\u5c3c\u4e9a
country_264 = \u5357\u6781\u6d32
country_265 = \u79d1\u7d22\u6c83
country_266 = \u5df4\u52d2\u65af\u5766\u9886\u571f
country_267 = \u897f\u6492\u54c8\u62c9
country_268 = \u6fb3\u5927\u5229\u4e9a\u5357\u6781\u9886\u5730
country_269 = \u7f57\u65af\u5c5e\u5730
country_270 = \u5f7c\u5f97\u4e00\u4e16\u5c9b
country_271 = \u6bdb\u5fb7\u7687\u540e\u5730
country_272 = \u82f1\u5c5e\u5357\u6781\u9886\u5730
OBP-30001 = \u627e\u4e0d\u5230\u94f6\u884c\u3002\u0020\u8bf7\u4e3a\u0020\u0042\u0041\u004e\u004b\u005f\u0049\u0044\u0020\u6307\u5b9a\u4e00\u4e2a\u6709\u6548\u503c

View File

@ -243,7 +243,14 @@ mail.smtp.port=25
token_expiration_weeks=4
## payment challenge answer timeout,default is 600 seconds/10 minutes
transaction_request_challenge_ttl=600
transactionRequest.challenge.ttl.seconds=600
## auth context update request challenge answer timeout,default is 600 seconds/10 minutes
userAuthContextUpdateRequest.challenge.ttl.seconds=600
# the allowed attempts to answer the same transactionRequest Challenge, default is 3 times
#answer_transactionRequest_challenge_allowed_attempts=3
@ -283,14 +290,6 @@ transactionRequests_challenge_threshold_SEPA=1000
# To set a currency for the above value:
#transactionRequests_challenge_currency=KRW
## For video conference meetings (createMeeting)
meeting.tokbox_enabled=false
meeting.tokbox_api_key=changeme
meeting.tokbox_api_secret=changeme
### Management modules
## RabbitMQ settings (used to communicate with HBCI project)

View File

@ -66,10 +66,11 @@ tests.port=8016
End of minimum settings
####################################
#if connector is mapped, set a database backend. If not set, this will be set to an in-memory h2 database by default
#you can use a no config needed h2 database by setting db.driver=org.h2.Driver and not including db.url
# if connector is mapped, set a database backend. If not set, this will be set to an in-memory h2 database by default
# you can use a no config needed h2 database by setting db.driver=org.h2.Driver and not including db.url
# Please note that since update o version 2.1.214 we use NON_KEYWORDS=VALUE to bypass reserved word issue in SQL statements
#db.driver=org.h2.Driver
#db.url=jdbc:h2:./lift_proto.db;DB_CLOSE_ON_EXIT=FALSE
#db.url=jdbc:h2:./lift_proto.db;NON_KEYWORDS=VALUE;DB_CLOSE_ON_EXIT=FALSE
#set this to false if you don't want the api payments call to work
payments_enabled=false

View File

@ -55,7 +55,7 @@ import code.bankconnectors.{Connector, ConnectorEndpoints}
import code.branches.MappedBranch
import code.cardattribute.MappedCardAttribute
import code.cards.{MappedPhysicalCard, PinReset}
import code.consent.MappedConsent
import code.consent.{ConsentRequest, MappedConsent}
import code.consumer.Consumers
import code.context.{MappedConsentAuthContext, MappedUserAuthContext, MappedUserAuthContextUpdate}
import code.crm.MappedCrmEvent
@ -246,14 +246,14 @@ class Boot extends MdcLoggable {
case Props.RunModes.Test =>
new StandardDBVendor(
driver,
APIUtil.getPropsValue("db.url") openOr "jdbc:h2:mem:OBPTest;DB_CLOSE_DELAY=-1",
APIUtil.getPropsValue("db.url") openOr Constant.h2DatabaseDefaultUrlValue,
APIUtil.getPropsValue("db.user").orElse(Empty),
APIUtil.getPropsValue("db.password").orElse(Empty)
)
case _ =>
new StandardDBVendor(
driver,
"jdbc:h2:mem:OBPTest;DB_CLOSE_DELAY=-1",
h2DatabaseDefaultUrlValue,
Empty, Empty)
}
@ -1004,6 +1004,7 @@ object ToSchemify {
MappedCustomerIdMapping,
MappedProductAttribute,
MappedConsent,
ConsentRequest,
MigrationScriptLog,
MethodRouting,
EndpointMapping,

View File

@ -31,12 +31,13 @@ import java.net.URLDecoder
import code.api.Constant._
import code.api.OAuthHandshake._
import code.api.builder.AccountInformationServiceAISApi.APIMethods_AccountInformationServiceAISApi
import code.api.util.APIUtil._
import code.api.util.APIUtil.{getClass, _}
import code.api.util.ErrorMessages.{InvalidDAuthHeaderToken, UserIsDeleted, UsernameHasBeenLocked, attemptedToOpenAnEmptyBox}
import code.api.util._
import code.api.v3_0_0.APIMethods300
import code.api.v3_1_0.APIMethods310
import code.api.v4_0_0.APIMethods400
import code.api.v4_0_0.{APIMethods400, OBPAPI4_0_0}
import code.api.v5_0_0.OBPAPI5_0_0
import code.loginattempts.LoginAttempt
import code.model.dataAccess.AuthUser
import code.util.Helper.MdcLoggable
@ -45,15 +46,18 @@ import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.{ApiVersion, ReflectUtils, ScannedApiVersion}
import net.liftweb.common.{Box, Full, _}
import net.liftweb.http.rest.RestHelper
import net.liftweb.http.{JsonResponse, LiftResponse, Req, S}
import net.liftweb.http.{JsonResponse, LiftResponse, LiftRules, Req, S, TransientRequestMemoize}
import net.liftweb.json.Extraction
import net.liftweb.json.JsonAST.JValue
import net.liftweb.util.Helpers
import net.liftweb.util.{Helpers, NamedPF, Props, ThreadGlobal}
import net.liftweb.util.Helpers.tryo
import java.util.{Locale, ResourceBundle}
import scala.collection.immutable.List
import scala.collection.mutable.ArrayBuffer
import scala.math.Ordering
import scala.util.control.NoStackTrace
import scala.xml.{Node, NodeSeq}
trait APIFailure{
val msg : String
@ -72,7 +76,76 @@ object APIFailure {
case class APIFailureNewStyle(failMsg: String,
failCode: Int = 400,
ccl: Option[CallContextLight] = None
)
){
def translatedErrorMessage = {
val errorCode = extractErrorMessageCode(failMsg)
val errorBody = extractErrorMessageBody(failMsg)
val localeUrlParameter = getHttpRequestUrlParam(ccl.map(_.url).getOrElse(""),"Locale")
val locale = I18NUtil.computeLocale(localeUrlParameter)
val liftCoreResourceBundle = tryo(ResourceBundle.getBundle(LiftRules.liftCoreResourceName, locale)).toList
val _resBundle = new ThreadGlobal[List[ResourceBundle]]
object resourceValueCache extends TransientRequestMemoize[(String, Locale), String]
def resourceBundles(loc: Locale): List[ResourceBundle] = {
_resBundle.box match {
case Full(bundles) => bundles
case _ => {
_resBundle.set(
LiftRules.resourceForCurrentLoc.vend() :::
LiftRules.resourceNames.flatMap(name => tryo{
if (Props.devMode) {
tryo{
val clz = this.getClass.getClassLoader.loadClass("java.util.ResourceBundle")
val meth = clz.getDeclaredMethods.
filter{m => m.getName == "clearCache" && m.getParameterTypes.length == 0}.
toList.head
meth.invoke(null)
}
}
List(ResourceBundle.getBundle(name, loc))
}.openOr(
NamedPF.applyBox((name, loc), LiftRules.resourceBundleFactories.toList).map(List(_)) openOr Nil
)))
_resBundle.value
}
}
}
def resourceBundleList: List[ResourceBundle] = resourceBundles(locale) ++ liftCoreResourceBundle
def ?!(str: String, resBundle: List[ResourceBundle]): String =
resBundle.flatMap(
r => tryo(
r.getObject(str) match {
case s: String => Full(s)
case n: Node => Full(n.text)
case ns: NodeSeq => Full(ns.text)
case _ => Empty
})
.flatMap(s => s)).find(s => true) getOrElse {
LiftRules.localizationLookupFailureNotice.foreach(_ (str, locale));
str
}
def ?(str: String, locale: Locale): String = resourceValueCache.get(
str ->
locale,
if(?!(str, resourceBundleList)==str) //If can not find the value from props, then return the default error body.
errorBody
else
?!(str, resourceBundleList)
)
val translatedErrorBody = ?(errorCode, locale)
s"$errorCode$translatedErrorBody"
}
}
//if you change this, think about backwards compatibility! All existing
//versions of the API return this failure message, so if you change it, make sure
@ -586,8 +659,9 @@ trait OBPRestHelper extends RestHelper with MdcLoggable {
apiPrefix:OBPEndpoint => OBPEndpoint,
autoValidateAll: Boolean = false): Unit = {
def isAutoValidate(doc: ResourceDoc): Boolean =
doc.isValidateEnabled || (autoValidateAll && !doc.isValidateDisabled && doc.implementedInApiVersion == version)
def isAutoValidate(doc: ResourceDoc): Boolean = { //note: only support v5.0.0 and v4.0.0 at the moment.
doc.isValidateEnabled || (autoValidateAll && !doc.isValidateDisabled && List(OBPAPI5_0_0.version,OBPAPI4_0_0.version).contains(doc.implementedInApiVersion))
}
for(route <- routes) {
// one endpoint can have multiple ResourceDocs, so here use filter instead of find, e.g APIMethods400.Implementations400.createTransactionRequest

View File

@ -248,7 +248,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
Caching.memoizeSyncWithProvider (Some(cacheKey.toString())) (getStaticResourceDocsTTL second) {
logger.debug(s"Generating OBP Resource Docs requestedApiVersion is $requestedApiVersion")
val resourceDocJson = resourceDocsToResourceDocJson(getResourceDocsList(requestedApiVersion), resourceDocTags, partialFunctionNames, isVersion4OrHigher)
val resourceDocJson = resourceDocsToResourceDocJson(getResourceDocsList(requestedApiVersion), resourceDocTags, partialFunctionNames, isVersion4OrHigher, languageParam)
resourceDocJson.map(resourceDocsJsonToJsonResponse)
}
}
@ -309,7 +309,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
val allDocs = staticDocs.map( _ ++ filteredDocs)
val resourceDocJson = resourceDocsToResourceDocJson(allDocs, resourceDocTags, partialFunctionNames, isVersion4OrHigher)
val resourceDocJson = resourceDocsToResourceDocJson(allDocs, resourceDocTags, partialFunctionNames, isVersion4OrHigher, languageParam)
resourceDocJson.map(resourceDocsJsonToJsonResponse)
}
}
@ -353,25 +353,27 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
case None => dynamicDocs
}
val resourceDocJson = resourceDocsToResourceDocJson(Some(filteredDocs), resourceDocTags, partialFunctionNames, isVersion4OrHigher)
val resourceDocJson = resourceDocsToResourceDocJson(Some(filteredDocs), resourceDocTags, partialFunctionNames, isVersion4OrHigher, languageParam)
resourceDocJson.map(resourceDocsJsonToJsonResponse)
}}}
private def resourceDocsToResourceDocJson(rd: Option[List[ResourceDoc]],
resourceDocTags: Option[List[ResourceDocTag]],
partialFunctionNames: Option[List[String]],
isVersion4OrHigher:Boolean): Option[ResourceDocsJson] =
resourceDocTags: Option[List[ResourceDocTag]],
partialFunctionNames: Option[List[String]],
isVersion4OrHigher:Boolean,
languageParam: Option[LanguageParam]): Option[ResourceDocsJson] = {
for {
resourceDocs <- rd
} yield {
// Filter
val rdFiltered = ResourceDocsAPIMethodsUtil.filterResourceDocs(resourceDocs, resourceDocTags, partialFunctionNames)
// Format the data as json
JSONFactory1_4_0.createResourceDocsJson(rdFiltered, isVersion4OrHigher)
JSONFactory1_4_0.createResourceDocsJson(rdFiltered, isVersion4OrHigher, languageParam)
}
}
private val getChineseVersionResourceDocs : Box[JsonResponse] = {
val stream = getClass().getClassLoader().getResourceAsStream("ResourceDocs/ResourceDocs-Chinese.json")
val chineseVersion = try {
@ -402,9 +404,9 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
List(apiTagDocumentation))
val exampleResourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(List(exampleResourceDoc), false)
val exampleResourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(List(exampleResourceDoc), false, None)
val exampleResourceDocsJsonV400 = JSONFactory1_4_0.createResourceDocsJson(List(exampleResourceDoc), true)
val exampleResourceDocsJsonV400 = JSONFactory1_4_0.createResourceDocsJson(List(exampleResourceDoc), true, None)
@ -578,7 +580,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
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)
val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, languageParam)
val resourceDocsJsonJValue = Full(resourceDocsJsonToJsonResponse(resourceDocsJson))
Future(resourceDocsJsonJValue.map(successJsonResponse(_)))
case _ =>
@ -918,6 +920,7 @@ object ResourceDocsAPIMethodsUtil extends MdcLoggable{
def stringToLanguageParam (x: String) : Option[LanguageParam] = x.toLowerCase match {
case "en" => Some(EN)
case "zh" => Some(ZH)
case "es" | "es_ES" => Some(ES)
case _ => Empty
}

View File

@ -3745,6 +3745,7 @@ object SwaggerDefinitionsJSON {
valid_from = Some(new Date()),
time_to_live = Some(3600)
)
val postConsentRequestJsonV310 = postConsentPhoneJsonV310.copy(consumer_id = None)
val consentsJsonV310 = ConsentsJsonV310(List(consentJsonV310))
@ -4658,6 +4659,33 @@ object SwaggerDefinitionsJSON {
consumer_id = consumerIdExample.value
)
val consentRequestResponseJson = ConsentRequestResponseJson(
consent_request_id = consentRequestIdExample.value,
payload = json.parse(consentRequestPayloadExample.value),
consumer_id = consumerIdExample.value
)
val consentJsonV500 = ConsentJsonV500(
consent_id = "9d429899-24f5-42c8-8565-943ffa6a7945",
jwt = "eyJhbGciOiJIUzI1NiJ9.eyJlbnRpdGxlbWVudHMiOltdLCJjcmVhdGVkQnlVc2VySWQiOiJhYjY1MzlhOS1iMTA1LTQ0ODktYTg4My0wYWQ4ZDZjNjE2NTciLCJzdWIiOiIyMWUxYzhjYy1mOTE4LTRlYWMtYjhlMy01ZTVlZWM2YjNiNGIiLCJhdWQiOiJlanpuazUwNWQxMzJyeW9tbmhieDFxbXRvaHVyYnNiYjBraWphanNrIiwibmJmIjoxNTUzNTU0ODk5LCJpc3MiOiJodHRwczpcL1wvd3d3Lm9wZW5iYW5rcHJvamVjdC5jb20iLCJleHAiOjE1NTM1NTg0OTksImlhdCI6MTU1MzU1NDg5OSwianRpIjoiMDlmODhkNWYtZWNlNi00Mzk4LThlOTktNjYxMWZhMWNkYmQ1Iiwidmlld3MiOlt7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAxIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifSx7ImFjY291bnRfaWQiOiJtYXJrb19wcml2aXRlXzAyIiwiYmFua19pZCI6ImdoLjI5LnVrLngiLCJ2aWV3X2lkIjoib3duZXIifV19.8cc7cBEf2NyQvJoukBCmDLT7LXYcuzTcSYLqSpbxLp4",
status = ConsentStatus.INITIATED.toString,
consent_request_id = Some(consentRequestIdExample.value)
)
val postConsentRequestJsonV500 = PostConsentRequestJsonV500(
everything = false,
account_access = List(AccountAccessV500(
account_routing = accountRoutingJsonV121,
view_id = viewIdExample.value
)),
entitlements = Some(List(PostConsentEntitlementJsonV310(bankIdExample.value, "CanGetCustomer"))),
consumer_id = Some(consumerIdExample.value),
phone_number = Some(mobileNumberExample.value),
email = Some(emailExample.value),
valid_from = Some(new Date()),
time_to_live = Some(3600)
)
//The common error or success format.
//Just some helper format to use in Json
case class NotSupportedYet()

View File

@ -8,6 +8,8 @@ import com.openbankproject.commons.util.ApiStandards
// Note: Import this with: import code.api.Constant._
object Constant extends MdcLoggable {
logger.info("Instantiating Constants")
final val h2DatabaseDefaultUrlValue = "jdbc:h2:mem:OBPTest_H2_v2.1.214;NON_KEYWORDS=VALUE;DB_CLOSE_DELAY=10"
final val HostName = APIUtil.getPropsValue("hostname").openOrThrowException(ErrorMessages.HostnameNotSpecified)
def localIdentityProvider = APIUtil.getPropsValue("local_identity_provider", HostName)

View File

@ -202,7 +202,7 @@ object DirectLogin extends RestHelper with MdcLoggable {
case "username" =>
checkUsernameString(parameterValue)
case "password" =>
validatePasswordOnUsage(parameterValue)
basicPasswordValidation(parameterValue)
case "consumer_key" =>
checkMediumAlphaNumeric(parameterValue)
case "token" =>

View File

@ -33,6 +33,7 @@ import java.nio.charset.Charset
import java.text.{ParsePosition, SimpleDateFormat}
import java.util.concurrent.ConcurrentHashMap
import java.util.{Calendar, Date, UUID}
import code.UserRefreshes.UserRefreshes
import code.accountholders.AccountHolders
import code.api.Constant._
@ -65,7 +66,7 @@ import code.scope.Scope
import code.usercustomerlinks.UserCustomerLink
import code.util.Helper.{MdcLoggable, SILENCE_IS_GOLDEN}
import code.util.{Helper, JsonSchemaUtil}
import code.views.Views
import code.views.{MapperViews, Views}
import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue
import com.alibaba.ttl.internal.javassist.CannotCompileException
import com.github.dwickern.macros.NameOf.{nameOf, nameOfType}
@ -105,8 +106,8 @@ import javassist.{ClassPool, LoaderClassPath}
import javassist.expr.{ExprEditor, MethodCall}
import org.apache.commons.io.IOUtils
import org.apache.commons.lang3.StringUtils
import java.security.AccessControlException
import scala.collection.mutable
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.concurrent.Future
@ -130,10 +131,10 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
val DateWithMsFormat = new SimpleDateFormat(DateWithMs)
val DateWithMsRollbackFormat = new SimpleDateFormat(DateWithMsRollback)
val DateWithDayExampleString: String = "2017-09-19"
val DateWithSecondsExampleString: String = "2017-09-19T02:31:05Z"
val DateWithMsExampleString: String = "2017-09-19T02:31:05.000Z"
val DateWithMsRollbackExampleString: String = "2017-09-19T02:31:05.000+0000"
val DateWithDayExampleString: String = "1100-01-01"
val DateWithSecondsExampleString: String = "1100-01-01T01:01:01Z"
val DateWithMsExampleString: String = "1100-01-01T01:01:01.000Z"
val DateWithMsRollbackExampleString: String = "1100-01-01T01:01:01.000+0000"
// Use a fixed date far into the future (rather than current date/time so that cache keys are more static)
// (Else caching is invalidated by constantly changing date)
@ -611,14 +612,14 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
def errorJsonResponse(message : String = "error", httpCode : Int = 400, callContextLight: Option[CallContextLight] = None)(implicit headers: CustomResponseHeaders = CustomResponseHeaders(Nil)) : JsonResponse = {
def check403(message: String): Boolean = {
message.contains(UserHasMissingRoles) ||
message.contains(UserNoPermissionAccessView) ||
message.contains(UserHasMissingRoles) ||
message.contains(UserNotSuperAdminOrMissRole) ||
message.contains(ConsumerHasMissingRoles)
message.contains(extractErrorMessageCode(UserHasMissingRoles)) ||
message.contains(extractErrorMessageCode(UserNoPermissionAccessView)) ||
message.contains(extractErrorMessageCode(UserHasMissingRoles)) ||
message.contains(extractErrorMessageCode(UserNotSuperAdminOrMissRole)) ||
message.contains(extractErrorMessageCode(ConsumerHasMissingRoles))
}
def check401(message: String): Boolean = {
message.contains(UserNotLoggedIn)
message.contains(extractErrorMessageCode(UserNotLoggedIn))
}
val (code, responseHeaders) =
message match {
@ -677,7 +678,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
* 1) length is >16 characters without validations but max length <= 512
* 2) or Min 10 characters with mixed numbers + letters + upper+lower case + at least one special character.
* */
def validatePasswordOnCreation(password: String): Boolean = {
def fullPasswordValidation(password: String): Boolean = {
/**
* (?=.*\d) //should contain at least one digit
* (?=.*[a-z]) //should contain at least one lower case
@ -688,9 +689,8 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
val regex =
"""^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~])([A-Za-z0-9!"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~]{10,16})$""".r
password match {
case password if(validatePasswordOnUsage(password) ==SILENCE_IS_GOLDEN) => true
case password if(password.length > 16 && password.length <= 512) => true
case regex(password) => true
case password if(password.length > 16 && password.length <= 512 && basicPasswordValidation(password) ==SILENCE_IS_GOLDEN) => true
case regex(password) if(basicPasswordValidation(password) ==SILENCE_IS_GOLDEN) => true
case _ => false
}
}
@ -725,7 +725,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
/** only A-Z, a-z, 0-9, all allowed characters for password and max length <= 512 */
/** also support space now */
def validatePasswordOnUsage(value:String): String ={
def basicPasswordValidation(value:String): String ={
val valueLength = value.length
val regex = """^([A-Za-z0-9!"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~ ]+)$""".r
value match {
@ -3038,8 +3038,10 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
throw new Exception("Empty Box not allowed")
case obj1@ParamFailure(m,e,c,af: APIFailureNewStyle) =>
val obj = (m,e, c) match {
case ("", Empty, Empty) => Empty ?~! af.failMsg
case _ => Failure (m, e, c) ?~! af.failMsg
case ("", Empty, Empty) =>
Empty ?~! af.translatedErrorMessage
case _ =>
Failure (m, e, c) ?~! af.translatedErrorMessage
}
val failuresMsg = filterMessage(obj)
val callContext = af.ccl.map(_.copy(httpCode = Some(af.failCode)))
@ -3326,7 +3328,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
* Note: The public views means you can use anonymous access which implies that the user is an optional value
*/
final def checkViewAccessAndReturnView(viewId : ViewId, bankIdAccountId: BankIdAccountId, user: Option[User], consumerId: Option[String] = None): Box[View] = {
val customView = Views.views.vend.customView(viewId, bankIdAccountId)
val customView = MapperViews.customView(viewId, bankIdAccountId)
customView match { // CHECK CUSTOM VIEWS
// 1st: View is Pubic and Public views are NOT allowed on this instance.
case Full(v) if(v.isPublic && !allowPublicViews) => Failure(PublicViewsNotAllowedOnThisInstance)
@ -3336,7 +3338,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
case Full(v) if(user.isDefined && user.get.hasAccountAccess(v, bankIdAccountId, consumerId)) => customView
// The user has NO account access via custom view
case _ =>
val systemView = Views.views.vend.systemView(viewId)
val systemView = MapperViews.systemView(viewId)
systemView match { // CHECK SYSTEM VIEWS
// 1st: View is Pubic and Public views are NOT allowed on this instance.
case Full(v) if(v.isPublic && !allowPublicViews) => Failure(PublicViewsNotAllowedOnThisInstance)
@ -4200,5 +4202,25 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
""".stripMargin
val transactionRequestChallengeTtl = APIUtil.getPropsAsLongValue("transaction_request_challenge_ttl", 600)
val transactionRequestChallengeTtl = APIUtil.getPropsAsLongValue("transactionRequest.challenge.ttl.seconds", 600)
val userAuthContextUpdateRequestChallengeTtl = APIUtil.getPropsAsLongValue("userAuthContextUpdateRequest.challenge.ttl.seconds", 600)
val obpErrorMessageCodeRegex = "^(OBP-\\d+):"
//eg: UserHasMissingRoles = "OBP-20006: User is missing one or more roles:" -->
// errorCode = "OBP-20006:"
// So far we support the i180n, we need to separate the errorCode and errorBody
def extractErrorMessageCode (errorMessage: String) = {
val regex = obpErrorMessageCodeRegex.r
regex.findFirstIn(errorMessage).mkString
}
//eg: UserHasMissingRoles = "OBP-20006: User is missing one or more roles:" -->
// errorBody = " User is missing one or more roles:"
// So far we support the i180n, we need to separate the errorCode and errorBody
def extractErrorMessageBody(errorMessage: String) = {
errorMessage.replaceFirst(obpErrorMessageCodeRegex,"")
}
val allowedAnswerTransactionRequestChallengeAttempts = APIUtil.getPropsAsIntValue("answer_transactionRequest_challenge_allowed_attempts").openOr(3)
}

View File

@ -69,7 +69,7 @@ object ErrorMessages {
val FXCurrencyCodeCombinationsNotSupported = "OBP-10004: ISO Currency code combination not supported for FX. Please modify the FROM_CURRENCY_CODE or TO_CURRENCY_CODE. "
val InvalidDateFormat = "OBP-10005: Invalid Date Format. Could not convert value to a Date."
val InvalidCurrency = "OBP-10006: Invalid Currency Value."
val IncorrectRoleName = "OBP-10007: Incorrect Role name: "
val IncorrectRoleName = "OBP-10007: Incorrect Role name:"
val CouldNotTransformJsonToInternalModel = "OBP-10008: Could not transform Json to internal model."
val CountNotSaveOrUpdateResource = "OBP-10009: Could not save or update resource."
val NotImplemented = "OBP-10010: Not Implemented "
@ -77,7 +77,7 @@ object ErrorMessages {
val maximumLimitExceeded = "OBP-10012: Invalid value. Maximum number is 10000."
val attemptedToOpenAnEmptyBox = "OBP-10013: Attempted to open an empty Box."
val cannotDecryptValueOfProperty = "OBP-10014: Could not decrypt value of property "
val AllowedValuesAre = "OBP-10015: Allowed values are: "
val AllowedValuesAre = "OBP-10015: Allowed values are:"
val InvalidFilterParameterFormat = "OBP-10016: Incorrect filter Parameters in URL. "
val InvalidUrl = "OBP-10017: Incorrect URL Format. "
val TooManyRequests = "OBP-10018: Too Many Requests."
@ -106,7 +106,7 @@ object ErrorMessages {
val FilterIsDeletedFormatError = s"OBP-10036: is_deleted parameter can only take two values: TRUE or FALSE!"
val InvalidApiVersionString = "OBP-00027: Invalid API Version string. We could not find the version specified."
val IncorrectTriggerName = "OBP-10028: Incorrect Trigger name: "
val IncorrectTriggerName = "OBP-10028: Incorrect Trigger name:"
val ScaMethodNotDefined = "OBP-10030: Strong customer authentication method is not defined at this instance."
@ -114,11 +114,11 @@ object ErrorMessages {
// Authentication / Authorisation / User messages (OBP-20XXX)
val UserNotLoggedIn = "OBP-20001: User not logged in. Authentication is required!"
val DirectLoginMissingParameters = "OBP-20002: These DirectLogin parameters are missing: "
val DirectLoginInvalidToken = "OBP-20003: This DirectLogin token is invalid or expired: "
val DirectLoginMissingParameters = "OBP-20002: These DirectLogin parameters are missing:"
val DirectLoginInvalidToken = "OBP-20003: This DirectLogin token is invalid or expired:"
val InvalidLoginCredentials = "OBP-20004: Invalid login credentials. Check username/password."
val UserNotFoundById = "OBP-20005: User not found. Please specify a valid value for USER_ID."
val UserHasMissingRoles = "OBP-20006: User is missing one or more roles: "
val UserHasMissingRoles = "OBP-20006: User is missing one or more roles:"
val UserNotFoundByEmail = "OBP-20007: User not found by email."
val InvalidConsumerKey = "OBP-20008: Invalid Consumer Key."
@ -146,13 +146,13 @@ object ErrorMessages {
val SystemViewsCanNotBeModified = "OBP-20021: System Views can not be modified. Only the created views can be modified."
val ViewDoesNotPermitAccess = "OBP-20022: View does not permit the access."
val ConsumerHasMissingRoles = "OBP-20023: Consumer is missing one or more roles: "
val ConsumerHasMissingRoles = "OBP-20023: Consumer is missing one or more roles:"
val ConsumerNotFoundById = "OBP-20024: Consumer not found. Please specify a valid value for CONSUMER_ID."
val ScopeNotFound = "OBP-20025: Scope not found. Please specify a valid value for SCOPE_ID."
val ConsumerDoesNotHaveScope = "OBP-20026: CONSUMER_ID does not have the SCOPE_ID "
val UserNotFoundByUsername = "OBP-20027: User not found by username."
val GatewayLoginMissingParameters = "OBP-20028: These GatewayLogin parameters are missing: "
val GatewayLoginMissingParameters = "OBP-20028: These GatewayLogin parameters are missing:"
val GatewayLoginUnknownError = "OBP-20029: Unknown Gateway login error."
val GatewayLoginHostPropertyMissing = "OBP-20030: Property gateway.host is not defined."
val GatewayLoginWhiteListAddresses = "OBP-20031: Gateway login can be done only from allowed addresses."
@ -172,7 +172,7 @@ object ErrorMessages {
val NotEnoughtSearchStatisticsResults = "OBP-20052: Result set too small. Will not be displayed for reasons of privacy."
val ElasticSearchEmptyQueryBody = "OBP-20053: The Elasticsearch query body cannot be empty"
val InvalidAmount = "OBP-20054: Invalid amount. Please specify a valid value for amount."
val MissingQueryParams = "OBP-20055: These query parameters are missing: "
val MissingQueryParams = "OBP-20055: These query parameters are missing:"
val ElasticSearchDisabled = "OBP-20056: Elasticsearch is disabled for this API instance."
val UserNotFoundByUserId = "OBP-20057: User not found by userId."
val ConsumerIsDisabled = "OBP-20058: Consumer is disabled."
@ -185,7 +185,7 @@ object ErrorMessages {
val UserIsDeleted = "OBP-20064: The user is deleted!"
val DAuthCannotGetOrCreateUser = "OBP-20065: Cannot get or create user during DAuth process."
val DAuthMissingParameters = "OBP-20066: These DAuth parameters are missing: "
val DAuthMissingParameters = "OBP-20066: These DAuth parameters are missing:"
val DAuthUnknownError = "OBP-20067: Unknown DAuth login error."
val DAuthHostPropertyMissing = "OBP-20068: Property dauth.host is not defined."
val DAuthWhiteListAddresses = "OBP-20069: DAuth login can be done only from allowed addresses."
@ -198,7 +198,7 @@ object ErrorMessages {
val UserAttributeNotFound = "OBP-20081: User Attribute not found by USER_ATTRIBUTE_ID."
val UserNotSuperAdminOrMissRole = "OBP-20101: Current User is not super admin or is missing entitlements: "
val UserNotSuperAdminOrMissRole = "OBP-20101: Current User is not super admin or is missing entitlements:"
val CannotGetOrCreateUser = "OBP-20102: Cannot get or create user."
val InvalidUserProvider = "OBP-20103: Invalid DAuth User Provider."
@ -267,7 +267,7 @@ object ErrorMessages {
val CreateBankError = "OBP-30020: Could not create the Bank"
val UpdateBankError = "OBP-30021: Could not update the Bank"
val NoViewPermission = "OBP-30022: The current view does not have the permission: "
val NoViewPermission = "OBP-30022: The current view does not have the permission:"
val UpdateConsumerError = "OBP-30023: Cannot update Consumer "
val CreateConsumerError = "OBP-30024: Could not create Consumer "
val CreateOAuth2ConsumerError = "OBP-30077: Could not create OAuth2 Consumer."
@ -467,7 +467,7 @@ object ErrorMessages {
val ConsentDisabled = "OBP-35007: Consents are not allowed at this instance. "
val ConsentHeaderNotFound = "OBP-35008: Cannot get Consent-Id. "
val ConsentAllowedScaMethods = "OBP-35009: Only SMS and EMAIL are supported as SCA methods. "
val SmsServerNotResponding = "OBP-35010: SMS server is not working or SMS server can not send the message to the phone number: "
val SmsServerNotResponding = "OBP-35010: SMS server is not working or SMS server can not send the message to the phone number:"
val AuthorizationNotFound = "OBP-35011: Resource identification of the related Consent authorisation sub-resource not found by AUTHORIZATION_ID. "
val ConsentAlreadyRevoked = "OBP-35012: Consent is already revoked. "
val RolesAllowedInConsent = "OBP-35013: Consents can only contain Roles that you already have access to."
@ -485,6 +485,8 @@ object ErrorMessages {
val ConsentUpdateStatusError = "OBP-35025: The Consent's status cannot be updated."
val ConsentUserCannotBeAdded = "OBP-35026: The Consent's User cannot be added."
val ConsentUserAuthContextCannotBeAdded = "OBP-35027: The Consent's User Auth Context cannot be added."
val ConsentRequestNotFound = "OBP-35028: Consent Request not found by CONSENT_REQUEST_ID. "
val ConsentRequestAlreadyUsed = "OBP-35029: The CONSENT_REQUEST_ID is used to create Consent. "
//Authorisations
val AuthorisationNotFound = "OBP-36001: Authorisation not found. Please specify valid values for PAYMENT_ID and AUTHORISATION_ID. "

View File

@ -1456,7 +1456,35 @@ object ExampleValue {
glossaryItems += makeGlossaryItem("direct_debit_id", directDebitIdExample)
lazy val consentIdExample = ConnectorField(NoExampleProvided,NoDescriptionProvided)
glossaryItems += makeGlossaryItem("consent_id", consentIdExample)
glossaryItems += makeGlossaryItem("consent_id", consentIdExample)
lazy val consentRequestPayloadExample = ConnectorField(
"""{
| "everything": false,
| "account_access": [
| {
| "account_routing": {
| "scheme": "AccountNumber",
| "address": "4930396"
| },
| "view_id": "owner"
| }
| ],
| "phone_number": "+44 07972 444 876",
| "valid_from": "2022-06-14T12:42:00Z",
| "time_to_live": 3600
|}""".stripMargin,
"The whole create consent request json body."
)
glossaryItems += makeGlossaryItem("payload", consentRequestPayloadExample)
lazy val consentRequestIdExample = ConnectorField (
"8ca8a7e4-6d02-40e3-a129-0b2bf89de9f0",
s"A string that MUST uniquely identify the Consent Request on this OBP instance."
)
glossaryItems += makeGlossaryItem("consent_request_id", consentRequestIdExample)
lazy val line2Example = ConnectorField(NoExampleProvided,NoDescriptionProvided)
glossaryItems += makeGlossaryItem("line2", line2Example)

View File

@ -993,7 +993,7 @@ object Glossary extends MdcLoggable {
|
|Body:
|
| { "legal_name":"Eveline Tripman", "mobile_phone_number":"+44 07972 444 876", "email":"eveline@example.com", "face_image":{ "url":"www.openbankproject", "date":"2017-09-19T00:00:00Z" }, "date_of_birth":"2017-09-19T00:00:00Z", "relationship_status":"single", "dependants":10, "dob_of_dependants":["2017-09-19T00:00:00Z"], "credit_rating":{ "rating":"OBP", "source":"OBP" }, "credit_limit":{ "currency":"EUR", "amount":"10" }, "highest_education_attained":"Master", "employment_status":"worker", "kyc_status":true, "last_ok_date":"2017-09-19T00:00:00Z", "title":"Dr.", "branch_id":"DERBY6", "name_suffix":"Sr"}
| { "legal_name":"Eveline Tripman", "mobile_phone_number":"+44 07972 444 876", "email":"eveline@example.com", "face_image":{ "url":"www.openbankproject", "date":"1100-01-01T00:00:00Z" }, "date_of_birth":"1100-01-01T00:00:00Z", "relationship_status":"single", "dependants":10, "dob_of_dependants":["1100-01-01T00:00:00Z"], "credit_rating":{ "rating":"OBP", "source":"OBP" }, "credit_limit":{ "currency":"EUR", "amount":"10" }, "highest_education_attained":"Master", "employment_status":"worker", "kyc_status":true, "last_ok_date":"1100-01-01T00:00:00Z", "title":"Dr.", "branch_id":"DERBY6", "name_suffix":"Sr"}
|
|Headers:
|

View File

@ -2,6 +2,8 @@ package code.api.util
import java.util.{Date, Locale}
import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue
import com.openbankproject.commons.model.enums.LanguageParam
import net.liftweb.http.S
import net.liftweb.util.Props
@ -31,5 +33,27 @@ object I18NUtil {
case Array(lang, country) => new Locale(lang, country)
case Array(lang, country, variant) => new Locale(lang, country, variant)
}
object ResourceDocTranslation {
def summary(operationId: String, language: Option[LanguageParam], default: String): String = {
language match {
case Some(value) =>
val webUiKey = s"webui_resource_doc_operation_id_${operationId}_summary_${value}"
getWebUiPropsValue(webUiKey, default)
case None =>
default
}
}
def description(operationId: String, language: Option[LanguageParam], default: String): String = {
language match {
case Some(value) =>
val webUiKey = s"webui_resource_doc_operation_id_${operationId}_description_${value}"
getWebUiPropsValue(webUiKey, default)
case None =>
default
}
}
}
}

View File

@ -148,6 +148,7 @@ object JwsUtil extends MdcLoggable {
val pathOfStandard = HashMap(
"BGv1.3"->"berlin-group/v1.3",
"OBPv4.0.0"->"obp/v4.0.0",
"OBPv5.0.0"->"obp/v5.0.0",
"OBPv3.1.0"->"obp/v3.1.0",
"UKv1.3"->"open-banking/v3.1"
).withDefaultValue("{Not found any standard to match}")

View File

@ -64,15 +64,15 @@ object Migration extends MdcLoggable {
addAccountAccessConsumerId()
populateTableViewDefinition()
populateTableAccountAccess()
generateAndPopulateMissingCustomerUUIDs()
generateAndPopulateMissingConsumersUUIDs()
generateAndPopulateMissingCustomerUUIDs(startedBeforeSchemifier)
generateAndPopulateMissingConsumersUUIDs(startedBeforeSchemifier)
populateTableRateLimiting()
updateTableViewDefinition()
bankAccountHoldersAndOwnerViewAccessInfo()
alterTableMappedConsent()
alterColumnChallengeAtTableMappedConsent()
alterTableOpenIDConnectToken()
alterTableMappedUserAuthContext()
alterTableMappedUserAuthContext(startedBeforeSchemifier)
alterTableMappedUserAuthContextUpdate()
populateNameAndAppTypeFieldsAtConsumerTable()
populateAzpAndSubFieldsAtConsumerTable()
@ -80,7 +80,7 @@ object Migration extends MdcLoggable {
populateSettlementBankAccounts()
alterColumnStatusAtTableMappedConsent()
alterColumnDetailsAtTableTransactionRequest()
deleteDuplicatedRowsInTheTableUserAuthContext()
deleteDuplicatedRowsInTheTableUserAuthContext(startedBeforeSchemifier)
populateTheFieldDeletedAtResourceUser(startedBeforeSchemifier)
populateTheFieldIsActiveAtProductAttribute(startedBeforeSchemifier)
alterColumnUsernameProviderFirstnameAndLastnameAtAuthUser(startedBeforeSchemifier)
@ -94,6 +94,7 @@ object Migration extends MdcLoggable {
alterWebhookColumnUrlLength()
dropConsentAuthContextDropIndex()
alterMappedExpectedChallengeAnswerChallengeTypeLength()
alterTransactionRequestChallengeChallengeTypeLength()
}
private def dummyScript(): Boolean = {
@ -123,36 +124,47 @@ object Migration extends MdcLoggable {
}
}
private def generateAndPopulateMissingCustomerUUIDs(): Boolean = {
val name = nameOf(generateAndPopulateMissingCustomerUUIDs)
runOnce(name) {
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
val isSuccessful = CustomerX.customerProvider.vend.populateMissingUUIDs()
val endDate = System.currentTimeMillis()
private def generateAndPopulateMissingCustomerUUIDs(startedBeforeSchemifier: Boolean): Boolean = {
if(startedBeforeSchemifier == true) {
logger.warn(s"Migration.database.generateAndPopulateMissingCustomerUUIDs(true) cannot be run before Schemifier.")
true
} else {
val name = nameOf(generateAndPopulateMissingCustomerUUIDs(startedBeforeSchemifier))
runOnce(name) {
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
val isSuccessful = CustomerX.customerProvider.vend.populateMissingUUIDs()
val endDate = System.currentTimeMillis()
val comment: String =
s"""Execute `generateAndPopulateMissingCustomerUUIDs`
|Duration: ${endDate - startDate} ms;
val comment: String =
s"""Execute `generateAndPopulateMissingCustomerUUIDs`
|Duration: ${endDate - startDate} ms;
""".stripMargin
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
}
}
}
private def generateAndPopulateMissingConsumersUUIDs(): Boolean = {
val name = nameOf(generateAndPopulateMissingConsumersUUIDs)
runOnce(name) {
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
val isSuccessful = Consumers.consumers.vend.populateMissingUUIDs()
val endDate = System.currentTimeMillis()
val comment: String =
s"""Execute `generateAndPopulateMissingConsumersUUIDs`
|Duration: ${endDate - startDate} ms;
private def generateAndPopulateMissingConsumersUUIDs(startedBeforeSchemifier: Boolean): Boolean = {
if(startedBeforeSchemifier == true) {
logger.warn(s"Migration.database.generateAndPopulateMissingConsumersUUIDs(true) cannot be run before Schemifier.")
true
} else {
val name = nameOf(generateAndPopulateMissingConsumersUUIDs(startedBeforeSchemifier))
runOnce(name) {
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
val isSuccessful = Consumers.consumers.vend.populateMissingUUIDs()
val endDate = System.currentTimeMillis()
val comment: String =
s"""Execute `generateAndPopulateMissingConsumersUUIDs`
|Duration: ${endDate - startDate} ms;
""".stripMargin
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
}
}
}
@ -207,10 +219,15 @@ object Migration extends MdcLoggable {
MigrationOfConsumer.populateAzpAndSub(name)
}
}
private def alterTableMappedUserAuthContext(): Boolean = {
val name = nameOf(alterTableMappedUserAuthContext)
runOnce(name) {
MigrationOfMappedUserAuthContext.dropUniqueIndex(name)
private def alterTableMappedUserAuthContext(startedBeforeSchemifier: Boolean): Boolean = {
if(startedBeforeSchemifier == true) {
logger.warn(s"Migration.database.alterTableMappedUserAuthContext(true) cannot be run before Schemifier.")
true
} else {
val name = nameOf(alterTableMappedUserAuthContext(startedBeforeSchemifier))
runOnce(name) {
MigrationOfMappedUserAuthContext.dropUniqueIndex(name)
}
}
}
private def alterTableMappedUserAuthContextUpdate(): Boolean = {
@ -243,10 +260,15 @@ object Migration extends MdcLoggable {
MigrationOfTransactionRequerst.alterColumnDetails(name)
}
}
private def deleteDuplicatedRowsInTheTableUserAuthContext(): Boolean = {
val name = nameOf(deleteDuplicatedRowsInTheTableUserAuthContext)
runOnce(name) {
MigrationOfUserAuthContext.removeDuplicates(name)
private def deleteDuplicatedRowsInTheTableUserAuthContext(startedBeforeSchemifier: Boolean): Boolean = {
if(startedBeforeSchemifier == true) {
logger.warn(s"Migration.database.deleteDuplicatedRowsInTheTableUserAuthContext(true) cannot be run before Schemifier.")
true
} else {
val name = nameOf(deleteDuplicatedRowsInTheTableUserAuthContext(startedBeforeSchemifier))
runOnce(name) {
MigrationOfUserAuthContext.removeDuplicates(name)
}
}
}
private def populateTheFieldDeletedAtResourceUser(startedBeforeSchemifier: Boolean): Boolean = {
@ -386,6 +408,13 @@ object Migration extends MdcLoggable {
}
}
private def alterTransactionRequestChallengeChallengeTypeLength(): Boolean = {
val name = nameOf(alterTransactionRequestChallengeChallengeTypeLength)
runOnce(name) {
MigrationOfTransactionRequestChallengeChallengeTypeLength.alterColumnChallengeChallengeTypeLength(name)
}
}
}
/**

View File

@ -8,10 +8,11 @@ import net.liftweb.mapper.{DB, Schemifier}
import net.liftweb.util.DefaultConnectionIdentifier
import scalikejdbc.DB.CPContext
import scalikejdbc._
import java.time.format.DateTimeFormatter
import java.time.{ZoneId, ZonedDateTime}
import code.api.Constant
object MigrationOfConsentAuthContextDropIndex {
val oneDayAgo = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(1)
@ -19,7 +20,7 @@ object MigrationOfConsentAuthContextDropIndex {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'")
private lazy val getDbConnectionParameters: (String, String, String) = {
val dbUrl = APIUtil.getPropsValue("db.url") openOr "jdbc:h2:mem:OBPTest;DB_CLOSE_DELAY=-1"
val dbUrl = APIUtil.getPropsValue("db.url") openOr Constant.h2DatabaseDefaultUrlValue
val username = dbUrl.split(";").filter(_.contains("user")).toList.headOption.map(_.split("=")(1))
val password = dbUrl.split(";").filter(_.contains("password")).toList.headOption.map(_.split("=")(1))
val dbUser = APIUtil.getPropsValue("db.user").orElse(username)

View File

@ -0,0 +1,57 @@
package code.api.util.migration
import code.api.util.APIUtil
import code.api.util.migration.Migration.{DbFunction, saveLog}
import code.transactionrequests.MappedTransactionRequest
import net.liftweb.common.Full
import net.liftweb.mapper.{DB, Schemifier}
import net.liftweb.util.DefaultConnectionIdentifier
import java.time.format.DateTimeFormatter
import java.time.{ZoneId, ZonedDateTime}
object MigrationOfTransactionRequestChallengeChallengeTypeLength {
val oneDayAgo = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(1)
val oneYearInFuture = ZonedDateTime.now(ZoneId.of("UTC")).plusYears(1)
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'")
def alterColumnChallengeChallengeTypeLength(name: String): Boolean = {
DbFunction.tableExists(MappedTransactionRequest, (DB.use(DefaultConnectionIdentifier){ conn => conn})) match {
case true =>
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
var isSuccessful = false
val executedSql =
DbFunction.maybeWrite(true, Schemifier.infoF _, DB.use(DefaultConnectionIdentifier){ conn => conn}) {
APIUtil.getPropsValue("db.driver") match {
case Full(value) if value.contains("com.microsoft.sqlserver.jdbc.SQLServerDriver") =>
() => "ALTER TABLE mappedtransactionrequest ALTER COLUMN mChallenge_ChallengeType varchar(100);"
case _ =>
() => "ALTER TABLE mappedtransactionrequest ALTER COLUMN mChallenge_ChallengeType TYPE character varying(100);"
}
}
val endDate = System.currentTimeMillis()
val comment: String =
s"""Executed SQL:
|$executedSql
|""".stripMargin
isSuccessful = true
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
case false =>
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
val isSuccessful = false
val endDate = System.currentTimeMillis()
val comment: String =
s"""${MappedTransactionRequest._dbTableNameLC} table does not exist""".stripMargin
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
}
}
}

View File

@ -3,6 +3,7 @@ package code.api.util.migration
import java.time.format.DateTimeFormatter
import java.time.{ZoneId, ZonedDateTime}
import code.api.Constant
import code.api.util.APIUtil
import code.api.util.migration.Migration.{DbFunction, saveLog}
import code.context.MappedUserAuthContext
@ -20,7 +21,7 @@ object MigrationOfUserAuthContext {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'")
private lazy val getDbConnectionParameters: (String, String, String) = {
val dbUrl = APIUtil.getPropsValue("db.url") openOr "jdbc:h2:mem:OBPTest;DB_CLOSE_DELAY=-1"
val dbUrl = APIUtil.getPropsValue("db.url") openOr Constant.h2DatabaseDefaultUrlValue
val username = dbUrl.split(";").filter(_.contains("user")).toList.headOption.map(_.split("=")(1))
val password = dbUrl.split(";").filter(_.contains("password")).toList.headOption.map(_.split("=")(1))
val dbUser = APIUtil.getPropsValue("db.user").orElse(username)
@ -51,6 +52,8 @@ object MigrationOfUserAuthContext {
// Make back up
DbFunction.makeBackUpOfTable(MappedUserAuthContext)
MappedUserAuthContext.findAll()
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit

View File

@ -1,12 +1,12 @@
package code.api.v1_4_0
import code.api.berlin.group.v1_3.JvalueCaseClass
import java.util.Date
import code.api.util.APIUtil.{EmptyBody, PrimaryDataBody, ResourceDoc}
import code.api.util.ApiTag.ResourceDocTag
import code.api.util.Glossary.glossaryItems
import code.api.util.{APIUtil, ApiRole, ConnectorField, CustomJsonFormats, ExampleValue, PegdownOptions}
import code.api.util.{APIUtil, ApiRole, ConnectorField, CustomJsonFormats, ExampleValue, I18NUtil, PegdownOptions}
import code.bankconnectors.LocalMappedConnector.getAllEndpointTagsBox
import com.openbankproject.commons.model.ListResult
import code.crm.CrmEvent.CrmEvent
@ -21,10 +21,11 @@ import net.liftweb.json.JsonAST.{JArray, JBool, JNothing, JObject, JValue}
import net.liftweb.util.StringHelpers
import code.util.Helper.MdcLoggable
import org.apache.commons.lang3.StringUtils
import java.util.concurrent.ConcurrentHashMap
import java.util.regex.Pattern
import com.openbankproject.commons.model.enums.LanguageParam
object JSONFactory1_4_0 extends MdcLoggable{
implicit def formats: Formats = CustomJsonFormats.formats
case class PostCustomerJson(
@ -452,7 +453,7 @@ object JSONFactory1_4_0 extends MdcLoggable{
private val createResourceDocJsonMemo = new ConcurrentHashMap[ResourceDoc, ResourceDocJson]
def createResourceDocJson(rd: ResourceDoc, isVersion4OrHigher:Boolean) : ResourceDocJson = {
def createResourceDocJson(rd: ResourceDoc, isVersion4OrHigher:Boolean, languageParam: Option[LanguageParam]) : ResourceDocJson = {
// if this calculate conversion already happened before, just return that value
// if not calculated before, just do conversion
val endpointTags = getAllEndpointTagsBox(rd.operationId).map(endpointTag =>ResourceDocTag(endpointTag.tagName))
@ -489,13 +490,20 @@ object JSONFactory1_4_0 extends MdcLoggable{
urlParametersDescription ++ exampleRequestBodyFieldsDescription ++ responseFieldsDescription
}
val description = resourceDocUpdatedTags.description.stripMargin.trim ++ fieldsDescription
val resourceDocDescription = I18NUtil.ResourceDocTranslation.description(
resourceDocUpdatedTags.operationId,
languageParam,
resourceDocUpdatedTags.description.stripMargin.trim
)
val description = resourceDocDescription ++ fieldsDescription
val summary = resourceDocUpdatedTags.summary.replaceFirst("""\.(\s*)$""", "$1") // remove the ending dot in summary
val translatedSummary = I18NUtil.ResourceDocTranslation.summary(resourceDocUpdatedTags.operationId, languageParam, summary)
ResourceDocJson(
operation_id = resourceDocUpdatedTags.operationId,
request_verb = resourceDocUpdatedTags.requestVerb,
request_url = resourceDocUpdatedTags.requestUrl,
summary = resourceDocUpdatedTags.summary.replaceFirst("""\.(\s*)$""", "$1"), // remove the ending dot in summary
summary = translatedSummary,
// Strip the margin character (|) and line breaks and convert from markdown to html
description = PegdownOptions.convertPegdownToHtmlTweaked(description), //.replaceAll("\n", ""),
description_markdown = description,
@ -516,14 +524,14 @@ object JSONFactory1_4_0 extends MdcLoggable{
})
}
def createResourceDocsJson(resourceDocList: List[ResourceDoc], isVersion4OrHigher:Boolean) : ResourceDocsJson = {
def createResourceDocsJson(resourceDocList: List[ResourceDoc], isVersion4OrHigher:Boolean, languageParam: Option[LanguageParam]) : ResourceDocsJson = {
if(isVersion4OrHigher){
ResourceDocsJson(
resourceDocList.map(createResourceDocJson(_,isVersion4OrHigher)),
resourceDocList.map(createResourceDocJson(_,isVersion4OrHigher, languageParam)),
meta=Some(ResourceDocMeta(new Date(), resourceDocList.length))
)
} else {
ResourceDocsJson(resourceDocList.map(createResourceDocJson(_,false)))
ResourceDocsJson(resourceDocList.map(createResourceDocJson(_,false, languageParam)))
}
}

View File

@ -1477,7 +1477,7 @@ trait APIMethods200 {
cc =>
for {
postedData <- tryo {json.extract[CreateUserJson]} ?~! ErrorMessages.InvalidJsonFormat
_ <- tryo(assert(validatePasswordOnCreation(postedData.password))) ?~! ErrorMessages.InvalidStrongPasswordFormat
_ <- tryo(assert(fullPasswordValidation(postedData.password))) ?~! ErrorMessages.InvalidStrongPasswordFormat
} yield {
if (AuthUser.find(By(AuthUser.username, postedData.username)).isEmpty) {
val userCreated = AuthUser.create
@ -1511,180 +1511,180 @@ trait APIMethods200 {
resourceDocs += ResourceDoc(
createMeeting,
apiVersion,
"createMeeting",
"POST",
"/banks/BANK_ID/meetings",
"Create Meeting (video conference/call)",
"""Create Meeting: Initiate a video conference/call with the bank.
|
|The Meetings resource contains meta data about video/other conference sessions, not the video/audio/chat itself.
|
|The actual conferencing is handled by external providers. Currently OBP supports tokbox video conferences (WIP).
|
|This is not a recomendation of tokbox per se.
|
|provider_id determines the provider of the meeting / video chat service. MUST be url friendly (no spaces).
|
|purpose_id explains the purpose of the chat. onboarding | mortgage | complaint etc. MUST be url friendly (no spaces).
|
|Login is required.
|
|This call is **experimental**. Currently staff_user_id is not set. Further calls will be needed to correctly set this.
""".stripMargin,
CreateMeetingJson("tokbox", "onboarding"),
meetingJson,
List(
UserNotLoggedIn,
MeetingApiKeyNotConfigured,
MeetingApiSecretNotConfigured,
InvalidBankIdFormat,
BankNotFound,
InvalidJsonFormat,
MeetingsNotSupported,
UnknownError
),
List(apiTagMeeting, apiTagCustomer, apiTagExperimental))
lazy val createMeeting: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "meetings" :: Nil JsonPost json -> _ => {
cc =>
if (APIUtil.getPropsAsBoolValue("meeting.tokbox_enabled", false)) {
for {
// TODO use these keys to get session and tokens from tokbox
_ <- APIUtil.getPropsValue("meeting.tokbox_api_key") ~> APIFailure(MeetingApiKeyNotConfigured, 403)
_ <- APIUtil.getPropsValue("meeting.tokbox_api_secret") ~> APIFailure(MeetingApiSecretNotConfigured, 403)
u <- cc.user ?~! UserNotLoggedIn
_ <- tryo(assert(isValidID(bankId.value)))?~! InvalidBankIdFormat
(bank, callContext) <- BankX(bankId, Some(cc)) ?~! BankNotFound
postedData <- tryo {json.extract[CreateMeetingJson]} ?~! InvalidJsonFormat
now = Calendar.getInstance().getTime()
sessionId <- tryo{code.opentok.OpenTokUtil.getSession.getSessionId()}
customerToken <- tryo{code.opentok.OpenTokUtil.generateTokenForPublisher(60)}
staffToken <- tryo{code.opentok.OpenTokUtil.generateTokenForModerator(60)}
meeting <- Meetings.meetingProvider.vend.createMeeting(bank.bankId, u, u, postedData.provider_id, postedData.purpose_id, now, sessionId, customerToken, staffToken
,null,null)//These two are used from V310
} yield {
// Format the data as V2.0.0 json
val json = JSONFactory200.createMeetingJSON(meeting)
successJsonResponse(Extraction.decompose(json), 201)
}
} else {
Full(errorJsonResponse(MeetingsNotSupported))
}
}
}
resourceDocs += ResourceDoc(
getMeetings,
apiVersion,
"getMeetings",
"GET",
"/banks/BANK_ID/meetings",
"Get Meetings",
"""Meetings contain meta data about, and are used to facilitate, video conferences / chats etc.
|
|The actual conference/chats are handled by external services.
|
|Login is required.
|
|This call is **experimental** and will require further authorisation in the future.
""".stripMargin,
emptyObjectJson,
meetingsJson,
List(
UserNotLoggedIn,
MeetingApiKeyNotConfigured,
MeetingApiSecretNotConfigured,
BankNotFound,
MeetingsNotSupported,
UnknownError),
List(apiTagMeeting, apiTagCustomer, apiTagExperimental))
lazy val getMeetings: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "meetings" :: Nil JsonGet _ => {
cc =>
if (APIUtil.getPropsAsBoolValue("meeting.tokbox_enabled", false)) {
for {
_ <- cc.user ?~! ErrorMessages.UserNotLoggedIn
(bank, callContext ) <- BankX(bankId, Some(cc)) ?~! BankNotFound
_ <- APIUtil.getPropsValue("meeting.tokbox_api_key") ~> APIFailure(ErrorMessages.MeetingApiKeyNotConfigured, 403)
_ <- APIUtil.getPropsValue("meeting.tokbox_api_secret") ~> APIFailure(ErrorMessages.MeetingApiSecretNotConfigured, 403)
u <- cc.user ?~! ErrorMessages.UserNotLoggedIn
(bank, callContext) <- BankX(bankId, Some(cc)) ?~! BankNotFound
// now = Calendar.getInstance().getTime()
meetings <- Meetings.meetingProvider.vend.getMeetings(bank.bankId, u)
}
yield {
// Format the data as V2.0.0 json
val json = JSONFactory200.createMeetingJSONs(meetings)
successJsonResponse(Extraction.decompose(json))
}
} else {
Full(errorJsonResponse(MeetingsNotSupported))
}
}
}
resourceDocs += ResourceDoc(
getMeeting,
apiVersion,
"getMeeting",
"GET",
"/banks/BANK_ID/meetings/MEETING_ID",
"Get Meeting",
"""Get Meeting specified by BANK_ID / MEETING_ID
|Meetings contain meta data about, and are used to facilitate, video conferences / chats etc.
|
|The actual conference/chats are handled by external services.
|
|Login is required.
|
|This call is **experimental** and will require further authorisation in the future.
""".stripMargin,
emptyObjectJson,
meetingJson,
List(
UserNotLoggedIn,
BankNotFound,
MeetingApiKeyNotConfigured,
MeetingApiSecretNotConfigured,
MeetingNotFound,
MeetingsNotSupported,
UnknownError
),
List(apiTagMeeting, apiTagKyc, apiTagCustomer, apiTagExperimental))
lazy val getMeeting: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "meetings" :: meetingId :: Nil JsonGet _ => {
cc =>
if (APIUtil.getPropsAsBoolValue("meeting.tokbox_enabled", false)) {
for {
u <- cc.user ?~! UserNotLoggedIn
(bank, callContext ) <- BankX(bankId, Some(cc)) ?~! BankNotFound
_ <- APIUtil.getPropsValue("meeting.tokbox_api_key") ~> APIFailure(ErrorMessages.MeetingApiKeyNotConfigured, 403)
_ <- APIUtil.getPropsValue("meeting.tokbox_api_secret") ~> APIFailure(ErrorMessages.MeetingApiSecretNotConfigured, 403)
(bank, callContext) <- BankX(bankId, Some(cc)) ?~! BankNotFound
meeting <- Meetings.meetingProvider.vend.getMeeting(bank.bankId, u, meetingId) ?~! {ErrorMessages.MeetingNotFound}
}
yield {
// Format the data as V2.0.0 json
val json = JSONFactory200.createMeetingJSON(meeting)
successJsonResponse(Extraction.decompose(json))
}
} else {
Full(errorJsonResponse(ErrorMessages.MeetingsNotSupported))
}
}
}
// resourceDocs += ResourceDoc(
// createMeeting,
// apiVersion,
// "createMeeting",
// "POST",
// "/banks/BANK_ID/meetings",
// "Create Meeting (video conference/call)",
// """Create Meeting: Initiate a video conference/call with the bank.
// |
// |The Meetings resource contains meta data about video/other conference sessions, not the video/audio/chat itself.
// |
// |The actual conferencing is handled by external providers. Currently OBP supports tokbox video conferences (WIP).
// |
// |This is not a recomendation of tokbox per se.
// |
// |provider_id determines the provider of the meeting / video chat service. MUST be url friendly (no spaces).
// |
// |purpose_id explains the purpose of the chat. onboarding | mortgage | complaint etc. MUST be url friendly (no spaces).
// |
// |Login is required.
// |
// |This call is **experimental**. Currently staff_user_id is not set. Further calls will be needed to correctly set this.
// """.stripMargin,
// CreateMeetingJson("tokbox", "onboarding"),
// meetingJson,
// List(
// UserNotLoggedIn,
// MeetingApiKeyNotConfigured,
// MeetingApiSecretNotConfigured,
// InvalidBankIdFormat,
// BankNotFound,
// InvalidJsonFormat,
// MeetingsNotSupported,
// UnknownError
// ),
// List(apiTagMeeting, apiTagCustomer, apiTagExperimental))
//
//
// lazy val createMeeting: OBPEndpoint = {
// case "banks" :: BankId(bankId) :: "meetings" :: Nil JsonPost json -> _ => {
// cc =>
// if (APIUtil.getPropsAsBoolValue("meeting.tokbox_enabled", false)) {
// for {
// // TODO use these keys to get session and tokens from tokbox
// _ <- APIUtil.getPropsValue("meeting.tokbox_api_key") ~> APIFailure(MeetingApiKeyNotConfigured, 403)
// _ <- APIUtil.getPropsValue("meeting.tokbox_api_secret") ~> APIFailure(MeetingApiSecretNotConfigured, 403)
// u <- cc.user ?~! UserNotLoggedIn
// _ <- tryo(assert(isValidID(bankId.value)))?~! InvalidBankIdFormat
// (bank, callContext) <- BankX(bankId, Some(cc)) ?~! BankNotFound
// postedData <- tryo {json.extract[CreateMeetingJson]} ?~! InvalidJsonFormat
// now = Calendar.getInstance().getTime()
// sessionId <- tryo{code.opentok.OpenTokUtil.getSession.getSessionId()}
// customerToken <- tryo{code.opentok.OpenTokUtil.generateTokenForPublisher(60)}
// staffToken <- tryo{code.opentok.OpenTokUtil.generateTokenForModerator(60)}
// meeting <- Meetings.meetingProvider.vend.createMeeting(bank.bankId, u, u, postedData.provider_id, postedData.purpose_id, now, sessionId, customerToken, staffToken
// ,null,null)//These two are used from V310
// } yield {
// // Format the data as V2.0.0 json
// val json = JSONFactory200.createMeetingJSON(meeting)
// successJsonResponse(Extraction.decompose(json), 201)
// }
// } else {
// Full(errorJsonResponse(MeetingsNotSupported))
// }
// }
// }
//
//
// resourceDocs += ResourceDoc(
// getMeetings,
// apiVersion,
// "getMeetings",
// "GET",
// "/banks/BANK_ID/meetings",
// "Get Meetings",
// """Meetings contain meta data about, and are used to facilitate, video conferences / chats etc.
// |
// |The actual conference/chats are handled by external services.
// |
// |Login is required.
// |
// |This call is **experimental** and will require further authorisation in the future.
// """.stripMargin,
// emptyObjectJson,
// meetingsJson,
// List(
// UserNotLoggedIn,
// MeetingApiKeyNotConfigured,
// MeetingApiSecretNotConfigured,
// BankNotFound,
// MeetingsNotSupported,
// UnknownError),
// List(apiTagMeeting, apiTagCustomer, apiTagExperimental))
//
//
// lazy val getMeetings: OBPEndpoint = {
// case "banks" :: BankId(bankId) :: "meetings" :: Nil JsonGet _ => {
// cc =>
// if (APIUtil.getPropsAsBoolValue("meeting.tokbox_enabled", false)) {
// for {
// _ <- cc.user ?~! ErrorMessages.UserNotLoggedIn
// (bank, callContext ) <- BankX(bankId, Some(cc)) ?~! BankNotFound
// _ <- APIUtil.getPropsValue("meeting.tokbox_api_key") ~> APIFailure(ErrorMessages.MeetingApiKeyNotConfigured, 403)
// _ <- APIUtil.getPropsValue("meeting.tokbox_api_secret") ~> APIFailure(ErrorMessages.MeetingApiSecretNotConfigured, 403)
// u <- cc.user ?~! ErrorMessages.UserNotLoggedIn
// (bank, callContext) <- BankX(bankId, Some(cc)) ?~! BankNotFound
// // now = Calendar.getInstance().getTime()
// meetings <- Meetings.meetingProvider.vend.getMeetings(bank.bankId, u)
// }
// yield {
// // Format the data as V2.0.0 json
// val json = JSONFactory200.createMeetingJSONs(meetings)
// successJsonResponse(Extraction.decompose(json))
// }
// } else {
// Full(errorJsonResponse(MeetingsNotSupported))
// }
// }
// }
//
//
//
// resourceDocs += ResourceDoc(
// getMeeting,
// apiVersion,
// "getMeeting",
// "GET",
// "/banks/BANK_ID/meetings/MEETING_ID",
// "Get Meeting",
// """Get Meeting specified by BANK_ID / MEETING_ID
// |Meetings contain meta data about, and are used to facilitate, video conferences / chats etc.
// |
// |The actual conference/chats are handled by external services.
// |
// |Login is required.
// |
// |This call is **experimental** and will require further authorisation in the future.
// """.stripMargin,
// emptyObjectJson,
// meetingJson,
// List(
// UserNotLoggedIn,
// BankNotFound,
// MeetingApiKeyNotConfigured,
// MeetingApiSecretNotConfigured,
// MeetingNotFound,
// MeetingsNotSupported,
// UnknownError
// ),
// List(apiTagMeeting, apiTagKyc, apiTagCustomer, apiTagExperimental))
//
//
// lazy val getMeeting: OBPEndpoint = {
// case "banks" :: BankId(bankId) :: "meetings" :: meetingId :: Nil JsonGet _ => {
// cc =>
// if (APIUtil.getPropsAsBoolValue("meeting.tokbox_enabled", false)) {
// for {
// u <- cc.user ?~! UserNotLoggedIn
// (bank, callContext ) <- BankX(bankId, Some(cc)) ?~! BankNotFound
// _ <- APIUtil.getPropsValue("meeting.tokbox_api_key") ~> APIFailure(ErrorMessages.MeetingApiKeyNotConfigured, 403)
// _ <- APIUtil.getPropsValue("meeting.tokbox_api_secret") ~> APIFailure(ErrorMessages.MeetingApiSecretNotConfigured, 403)
// (bank, callContext) <- BankX(bankId, Some(cc)) ?~! BankNotFound
// meeting <- Meetings.meetingProvider.vend.getMeeting(bank.bankId, u, meetingId) ?~! {ErrorMessages.MeetingNotFound}
// }
// yield {
// // Format the data as V2.0.0 json
// val json = JSONFactory200.createMeetingJSON(meeting)
// successJsonResponse(Extraction.decompose(json))
// }
// } else {
// Full(errorJsonResponse(ErrorMessages.MeetingsNotSupported))
// }
// }
// }
resourceDocs += ResourceDoc(

View File

@ -169,9 +169,9 @@ object OBPAPI2_0_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations2_0_0.createAccount,
Implementations2_0_0.getTransactionTypes,
Implementations2_0_0.createUser,
Implementations2_0_0.createMeeting,
Implementations2_0_0.getMeetings,
Implementations2_0_0.getMeeting,
// Implementations2_0_0.createMeeting,
// Implementations2_0_0.getMeetings,
// Implementations2_0_0.getMeeting,
Implementations2_0_0.createCustomer,
Implementations2_0_0.getCurrentUser,
Implementations2_0_0.getUser,

View File

@ -140,7 +140,7 @@ object OBPAPI2_1_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations2_0_0.addSocialMediaHandle ::
Implementations2_0_0.getPrivateAccountsAtOneBank ::
Implementations2_0_0.createAccount ::
Implementations2_0_0.createMeeting ::
// Implementations2_0_0.createMeeting ::
Implementations2_0_0.createUser ::
Implementations2_0_0.createUserCustomerLinks ::
Implementations2_0_0.deleteEntitlement ::
@ -155,8 +155,8 @@ object OBPAPI2_1_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations2_0_0.getKycDocuments ::
Implementations2_0_0.getKycMedia ::
Implementations2_0_0.getKycStatuses ::
Implementations2_0_0.getMeeting ::
Implementations2_0_0.getMeetings ::
// Implementations2_0_0.getMeeting ::
// Implementations2_0_0.getMeetings ::
Implementations2_0_0.getPermissionForUserForBankAccount ::
Implementations2_0_0.getPermissionsForBankAccount ::
Implementations2_0_0.getSocialMediaHandles ::

View File

@ -115,7 +115,7 @@ object OBPAPI2_2_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations2_0_0.getPrivateAccountsAtOneBank ::
//now in V220
//Implementations2_0_0.createAccount ::
Implementations2_0_0.createMeeting ::
// Implementations2_0_0.createMeeting ::
Implementations2_0_0.createUser ::
Implementations2_0_0.createUserCustomerLinks ::
Implementations2_0_0.deleteEntitlement ::
@ -130,8 +130,8 @@ object OBPAPI2_2_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations2_0_0.getKycDocuments ::
Implementations2_0_0.getKycMedia ::
Implementations2_0_0.getKycStatuses ::
Implementations2_0_0.getMeeting ::
Implementations2_0_0.getMeetings ::
// Implementations2_0_0.getMeeting ::
// Implementations2_0_0.getMeetings ::
Implementations2_0_0.getPermissionForUserForBankAccount ::
Implementations2_0_0.getPermissionsForBankAccount ::
Implementations2_0_0.getSocialMediaHandles ::

View File

@ -151,7 +151,7 @@ object OBPAPI3_0_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations2_0_0.getPrivateAccountsAtOneBank ::
//now in V220
//Implementations2_0_0.createAccount ::
Implementations2_0_0.createMeeting ::
// Implementations2_0_0.createMeeting ::
Implementations2_0_0.createUser ::
Implementations2_0_0.createUserCustomerLinks ::
Implementations2_0_0.deleteEntitlement ::
@ -166,8 +166,8 @@ object OBPAPI3_0_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
Implementations2_0_0.getKycDocuments ::
Implementations2_0_0.getKycMedia ::
Implementations2_0_0.getKycStatuses ::
Implementations2_0_0.getMeeting ::
Implementations2_0_0.getMeetings ::
// Implementations2_0_0.getMeeting ::
// Implementations2_0_0.getMeetings ::
Implementations2_0_0.getPermissionsForBankAccount ::
Implementations2_0_0.getSocialMediaHandles ::
Implementations2_0_0.getTransactionTypes ::

View File

@ -3,7 +3,6 @@ package code.api.v3_1_0
import java.text.SimpleDateFormat
import java.util.UUID
import java.util.regex.Pattern
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.ResourceDocs1_4_0.{MessageDocsSwaggerDefinitions, ResourceDocsAPIMethodsUtil, SwaggerDefinitionsJSON, SwaggerJSONFactory}
import code.api.util.APIUtil.{getWebUIPropsPairs, _}
@ -22,7 +21,7 @@ import code.api.v3_0_0.JSONFactory300.createAdapterInfoJson
import code.api.v3_1_0.JSONFactory310._
import code.bankconnectors.rest.RestConnector_vMar2019
import code.bankconnectors.{Connector, LocalMappedConnector}
import code.consent.{ConsentStatus, Consents}
import code.consent.{ConsentRequests, ConsentStatus, Consents}
import code.consumer.Consumers
import code.context.UserAuthContextUpdateProvider
import code.entitlement.Entitlement
@ -1425,7 +1424,7 @@ trait APIMethods310 {
json.extract[PostUserAuthContextJson]
}
(user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
(userAuthContext, callContext) <- NewStyle.function.createUserAuthContext(user, postedData.key, postedData.value, callContext)
(userAuthContext, callContext) <- NewStyle.function.createUserAuthContext(user, postedData.key.trim, postedData.value.trim, callContext)
} yield {
(JSONFactory310.createUserAuthContextJson(userAuthContext), HttpCode.`201`(callContext))
}
@ -3507,11 +3506,13 @@ trait APIMethods310 {
}
case None => Future(None, "Any application")
}
challengeAnswer = Props.mode match {
case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment
case _ => Random.nextInt(99999999).toString()
}
createdConsent <- Future(Consents.consentProvider.vend.createConsent(user, challengeAnswer)) map {
createdConsent <- Future(Consents.consentProvider.vend.createObpConsent(user, challengeAnswer, None)) map {
i => connectorEmptyResponse(i, callContext)
}
consentJWT =

View File

@ -529,6 +529,7 @@ case class PostConsentBodyCommonJson(
views: List[PostConsentViewJsonV310],
entitlements: List[PostConsentEntitlementJsonV310],
consumer_id: Option[String],
consent_request_id: Option[String],
valid_from: Option[Date],
time_to_live: Option[Long]
) extends PostConsentCommonBody

View File

@ -3,6 +3,7 @@ package code.api.v4_0_0
import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util.{Calendar, Date}
import code.DynamicData.{DynamicData, DynamicDataProvider}
import code.DynamicEndpoint.DynamicEndpointSwagger
import code.accountattribute.AccountAttributeX
@ -42,7 +43,7 @@ import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider
import code.authtypevalidation.JsonAuthTypeValidation
import code.bankconnectors.{Connector, DynamicConnector, InternalConnector}
import code.connectormethod.{JsonConnectorMethod, JsonConnectorMethodMethodBody}
import code.consent.{ConsentStatus, Consents}
import code.consent.{ConsentRequests, ConsentStatus, Consents}
import code.dynamicEntity.{DynamicEntityCommons, ReferenceType}
import code.dynamicMessageDoc.JsonDynamicMessageDoc
import code.dynamicResourceDoc.JsonDynamicResourceDoc
@ -909,379 +910,421 @@ trait APIMethods400 {
Some(List(canCreateAnyTransactionRequest)))
// Different Transaction Request approaches:
lazy val createTransactionRequestAccount = createTransactionRequest
lazy val createTransactionRequestAccountOtp = createTransactionRequest
lazy val createTransactionRequestSepa = createTransactionRequest
lazy val createTransactionRequestCounterparty = createTransactionRequest
lazy val createTransactionRequestRefund = createTransactionRequest
lazy val createTransactionRequestFreeForm = createTransactionRequest
lazy val createTransactionRequestSimple = createTransactionRequest
def createTransactionRequest(bankId: BankId, accountId: AccountId, viewId: ViewId, transactionRequestType: TransactionRequestType, json: JValue): Future[(TransactionRequestWithChargeJSON400, Option[CallContext])] = {
for {
(Full(u), fromAccount, callContext) <- SS.userAccount
_ <- NewStyle.function.isEnabledTransactionRequests(callContext)
_ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext) {
isValidID(accountId.value)
}
_ <- Helper.booleanToFuture(InvalidBankIdFormat, cc=callContext) {
isValidID(bankId.value)
}
// This handles the above cases
lazy val createTransactionRequest: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
TransactionRequestType(transactionRequestType) :: "transaction-requests" :: Nil JsonPost json -> _ => {
cc =>
for {
(Full(u), fromAccount, callContext) <- SS.userAccount
_ <- NewStyle.function.isEnabledTransactionRequests(callContext)
_ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext) {
isValidID(accountId.value)
}
_ <- Helper.booleanToFuture(InvalidBankIdFormat, cc=callContext) {
isValidID(bankId.value)
}
account = BankIdAccountId(bankId, accountId)
_ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest(viewId, account, u, callContext)
account = BankIdAccountId(bankId, accountId)
_ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest(viewId, account, u, callContext)
_ <- Helper.booleanToFuture(s"${InvalidTransactionRequestType}: '${transactionRequestType.value}'. Current Sandbox does not support it. ", cc=callContext) {
APIUtil.getPropsValue("transactionRequests_supported_types", "").split(",").contains(transactionRequestType.value)
}
_ <- Helper.booleanToFuture(s"${InvalidTransactionRequestType}: '${transactionRequestType.value}'. Current Sandbox does not support it. ", cc=callContext) {
APIUtil.getPropsValue("transactionRequests_supported_types", "").split(",").contains(transactionRequestType.value)
}
transactionRequestTypeValue <- NewStyle.function.tryons(s"$InvalidTransactionRequestType: '${transactionRequestType.value}'. OBP does not support it.", 400, callContext) {
TransactionRequestTypes.withName(transactionRequestType.value)
}
transactionRequestTypeValue <- NewStyle.function.tryons(s"$InvalidTransactionRequestType: '${transactionRequestType.value}'. OBP does not support it.", 400, callContext) {
TransactionRequestTypes.withName(transactionRequestType.value)
}
// Check the input JSON format, here is just check the common parts of all four types
transDetailsJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $TransactionRequestBodyCommonJSON ", 400, callContext) {
json.extract[TransactionRequestBodyCommonJSON]
}
// Check the input JSON format, here is just check the common parts of all four types
transDetailsJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $TransactionRequestBodyCommonJSON ", 400, callContext) {
json.extract[TransactionRequestBodyCommonJSON]
}
transactionAmountNumber <- NewStyle.function.tryons(s"$InvalidNumber Current input is ${transDetailsJson.value.amount} ", 400, callContext) {
BigDecimal(transDetailsJson.value.amount)
}
transactionAmountNumber <- NewStyle.function.tryons(s"$InvalidNumber Current input is ${transDetailsJson.value.amount} ", 400, callContext) {
BigDecimal(transDetailsJson.value.amount)
}
_ <- Helper.booleanToFuture(s"${NotPositiveAmount} Current input is: '${transactionAmountNumber}'", cc=callContext) {
transactionAmountNumber > BigDecimal("0")
}
_ <- Helper.booleanToFuture(s"${NotPositiveAmount} Current input is: '${transactionAmountNumber}'", cc=callContext) {
transactionAmountNumber > BigDecimal("0")
}
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", cc=callContext) {
isValidCurrencyISOCode(transDetailsJson.value.currency)
}
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", cc=callContext) {
isValidCurrencyISOCode(transDetailsJson.value.currency)
}
// Prevent default value for transaction request type (at least).
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", cc=callContext) {
isValidCurrencyISOCode(transDetailsJson.value.currency)
}
// Prevent default value for transaction request type (at least).
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", cc=callContext) {
isValidCurrencyISOCode(transDetailsJson.value.currency)
}
(createdTransactionRequest, callContext) <- transactionRequestTypeValue match {
case REFUND => {
for {
transactionRequestBodyRefundJson <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $ACCOUNT json format", 400, callContext) {
json.extract[TransactionRequestBodyRefundJsonV400]
}
(createdTransactionRequest, callContext) <- transactionRequestTypeValue match {
case REFUND => {
for {
transactionRequestBodyRefundJson <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $ACCOUNT json format", 400, callContext) {
json.extract[TransactionRequestBodyRefundJsonV400]
}
transactionId = TransactionId(transactionRequestBodyRefundJson.refund.transaction_id)
transactionId = TransactionId(transactionRequestBodyRefundJson.refund.transaction_id)
(fromAccount, toAccount, transaction, callContext) <- transactionRequestBodyRefundJson.to match {
case Some(refundRequestTo) if refundRequestTo.account_id.isDefined && refundRequestTo.bank_id.isDefined =>
val toBankId = BankId(refundRequestTo.bank_id.get)
val toAccountId = AccountId(refundRequestTo.account_id.get)
for {
(transaction, callContext) <- NewStyle.function.getTransaction(fromAccount.bankId, fromAccount.accountId, transactionId, callContext)
(toAccount, callContext) <- NewStyle.function.checkBankAccountExists(toBankId, toAccountId, callContext)
} yield (fromAccount, toAccount, transaction, callContext)
(fromAccount, toAccount, transaction, callContext) <- transactionRequestBodyRefundJson.to match {
case Some(refundRequestTo) if refundRequestTo.account_id.isDefined && refundRequestTo.bank_id.isDefined =>
val toBankId = BankId(refundRequestTo.bank_id.get)
val toAccountId = AccountId(refundRequestTo.account_id.get)
for {
(transaction, callContext) <- NewStyle.function.getTransaction(fromAccount.bankId, fromAccount.accountId, transactionId, callContext)
(toAccount, callContext) <- NewStyle.function.checkBankAccountExists(toBankId, toAccountId, callContext)
} yield (fromAccount, toAccount, transaction, callContext)
case Some(refundRequestTo) if refundRequestTo.counterparty_id.isDefined =>
val toCounterpartyId = CounterpartyId(refundRequestTo.counterparty_id.get)
for {
(toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(toCounterpartyId, callContext)
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, isOutgoingAccount = true, callContext)
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
toCounterparty.isBeneficiary
}
(transaction, callContext) <- NewStyle.function.getTransaction(fromAccount.bankId, fromAccount.accountId, transactionId, callContext)
} yield (fromAccount, toAccount, transaction, callContext)
case Some(refundRequestTo) if refundRequestTo.counterparty_id.isDefined =>
val toCounterpartyId = CounterpartyId(refundRequestTo.counterparty_id.get)
for {
(toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(toCounterpartyId, callContext)
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, isOutgoingAccount = true, callContext)
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
toCounterparty.isBeneficiary
}
(transaction, callContext) <- NewStyle.function.getTransaction(fromAccount.bankId, fromAccount.accountId, transactionId, callContext)
} yield (fromAccount, toAccount, transaction, callContext)
case None if transactionRequestBodyRefundJson.from.isDefined =>
val fromCounterpartyId = CounterpartyId(transactionRequestBodyRefundJson.from.get.counterparty_id)
val toAccount = fromAccount
for {
(fromCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(fromCounterpartyId, callContext)
fromAccount <- NewStyle.function.getBankAccountFromCounterparty(fromCounterparty, isOutgoingAccount = false, callContext)
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
fromCounterparty.isBeneficiary
}
(transaction, callContext) <- NewStyle.function.getTransaction(toAccount.bankId, toAccount.accountId, transactionId, callContext)
} yield (fromAccount, toAccount, transaction, callContext)
}
case None if transactionRequestBodyRefundJson.from.isDefined =>
val fromCounterpartyId = CounterpartyId(transactionRequestBodyRefundJson.from.get.counterparty_id)
val toAccount = fromAccount
for {
(fromCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(fromCounterpartyId, callContext)
fromAccount <- NewStyle.function.getBankAccountFromCounterparty(fromCounterparty, isOutgoingAccount = false, callContext)
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
fromCounterparty.isBeneficiary
}
(transaction, callContext) <- NewStyle.function.getTransaction(toAccount.bankId, toAccount.accountId, transactionId, callContext)
} yield (fromAccount, toAccount, transaction, callContext)
}
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodyRefundJson)(Serialization.formats(NoTypeHints))
}
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodyRefundJson)(Serialization.formats(NoTypeHints))
}
_ <- Helper.booleanToFuture(s"${RefundedTransaction} Current input amount is: '${transDetailsJson.value.amount}'. It can not be more than the original amount(${(transaction.amount).abs})", cc=callContext) {
(transaction.amount).abs >= transactionAmountNumber
}
//TODO, we need additional field to guarantee the transaction is refunded...
// _ <- Helper.booleanToFuture(s"${RefundedTransaction}") {
// !((transaction.description.toString contains(" Refund to ")) && (transaction.description.toString contains(" and transaction_id(")))
// }
_ <- Helper.booleanToFuture(s"${RefundedTransaction} Current input amount is: '${transDetailsJson.value.amount}'. It can not be more than the original amount(${(transaction.amount).abs})", cc=callContext) {
(transaction.amount).abs >= transactionAmountNumber
}
//TODO, we need additional field to guarantee the transaction is refunded...
// _ <- Helper.booleanToFuture(s"${RefundedTransaction}") {
// !((transaction.description.toString contains(" Refund to ")) && (transaction.description.toString contains(" and transaction_id(")))
// }
//we add the extra info (counterparty name + transaction_id) for this special Refund endpoint.
newDescription = s"${transactionRequestBodyRefundJson.description} - Refund for transaction_id: (${transactionId.value}) to ${transaction.otherAccount.counterpartyName}"
//we add the extra info (counterparty name + transaction_id) for this special Refund endpoint.
newDescription = s"${transactionRequestBodyRefundJson.description} - Refund for transaction_id: (${transactionId.value}) to ${transaction.otherAccount.counterpartyName}"
//This is the refund endpoint, the original fromAccount is the `toAccount` which will receive money.
refundToAccount = fromAccount
//This is the refund endpoint, the original toAccount is the `fromAccount` which will lose money.
refundFromAccount = toAccount
//This is the refund endpoint, the original fromAccount is the `toAccount` which will receive money.
refundToAccount = fromAccount
//This is the refund endpoint, the original toAccount is the `fromAccount` which will lose money.
refundFromAccount = toAccount
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
refundFromAccount,
refundToAccount,
transactionRequestType,
transactionRequestBodyRefundJson.copy(description = newDescription),
transDetailsSerialized,
sharedChargePolicy.toString,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
refundFromAccount,
refundToAccount,
transactionRequestType,
transactionRequestBodyRefundJson.copy(description = newDescription),
transDetailsSerialized,
sharedChargePolicy.toString,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"
_ <- NewStyle.function.createOrUpdateTransactionRequestAttribute(
bankId = bankId,
transactionRequestId = createdTransactionRequest.id,
transactionRequestAttributeId = None,
name = "original_transaction_id",
attributeType = TransactionRequestAttributeType.withName("STRING"),
value = transactionId.value,
callContext = callContext
)
_ <- NewStyle.function.createOrUpdateTransactionRequestAttribute(
refundReasonCode = transactionRequestBodyRefundJson.refund.reason_code
_ <- if (refundReasonCode.nonEmpty) {
NewStyle.function.createOrUpdateTransactionRequestAttribute(
bankId = bankId,
transactionRequestId = createdTransactionRequest.id,
transactionRequestAttributeId = None,
name = "original_transaction_id",
name = "refund_reason_code",
attributeType = TransactionRequestAttributeType.withName("STRING"),
value = transactionId.value,
callContext = callContext
)
value = refundReasonCode,
callContext = callContext)
} else Future.successful()
refundReasonCode = transactionRequestBodyRefundJson.refund.reason_code
_ <- if (refundReasonCode.nonEmpty) {
NewStyle.function.createOrUpdateTransactionRequestAttribute(
bankId = bankId,
transactionRequestId = createdTransactionRequest.id,
transactionRequestAttributeId = None,
name = "refund_reason_code",
attributeType = TransactionRequestAttributeType.withName("STRING"),
value = refundReasonCode,
callContext = callContext)
} else Future.successful()
(newTransactionRequestStatus, callContext) <- NewStyle.function.notifyTransactionRequest(refundFromAccount, refundToAccount, createdTransactionRequest, callContext)
_ <- Future(Connector.connector.vend.saveTransactionRequestStatusImpl(createdTransactionRequest.id, newTransactionRequestStatus.toString))
createdTransactionRequest <- Future(createdTransactionRequest.copy(status = newTransactionRequestStatus.toString))
(newTransactionRequestStatus, callContext) <- NewStyle.function.notifyTransactionRequest(refundFromAccount, refundToAccount, createdTransactionRequest, callContext)
_ <- Future(Connector.connector.vend.saveTransactionRequestStatusImpl(createdTransactionRequest.id, newTransactionRequestStatus.toString))
createdTransactionRequest <- Future(createdTransactionRequest.copy(status = newTransactionRequestStatus.toString))
} yield (createdTransactionRequest, callContext)
}
case ACCOUNT | SANDBOX_TAN => {
for {
transactionRequestBodySandboxTan <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $ACCOUNT json format", 400, callContext) {
json.extract[TransactionRequestBodySandBoxTanJSON]
}
toBankId = BankId(transactionRequestBodySandboxTan.to.bank_id)
toAccountId = AccountId(transactionRequestBodySandboxTan.to.account_id)
(toAccount, callContext) <- NewStyle.function.checkBankAccountExists(toBankId, toAccountId, callContext)
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodySandboxTan)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transactionRequestBodySandboxTan,
transDetailsSerialized,
sharedChargePolicy.toString,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"
} yield (createdTransactionRequest, callContext)
}
case ACCOUNT_OTP => {
for {
transactionRequestBodySandboxTan <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $ACCOUNT json format", 400, callContext) {
json.extract[TransactionRequestBodySandBoxTanJSON]
}
toBankId = BankId(transactionRequestBodySandboxTan.to.bank_id)
toAccountId = AccountId(transactionRequestBodySandboxTan.to.account_id)
(toAccount, callContext) <- NewStyle.function.checkBankAccountExists(toBankId, toAccountId, callContext)
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodySandboxTan)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transactionRequestBodySandboxTan,
transDetailsSerialized,
sharedChargePolicy.toString,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"
} yield (createdTransactionRequest, callContext)
}
case COUNTERPARTY => {
for {
//For COUNTERPARTY, Use the counterpartyId to find the toCounterparty and set up the toAccount
transactionRequestBodyCounterparty <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $COUNTERPARTY json format", 400, callContext) {
json.extract[TransactionRequestBodyCounterpartyJSON]
}
toCounterpartyId = transactionRequestBodyCounterparty.to.counterparty_id
(toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(toCounterpartyId), callContext)
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
// Check we can send money to it.
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
toCounterparty.isBeneficiary
}
chargePolicy = transactionRequestBodyCounterparty.charge_policy
_ <- Helper.booleanToFuture(s"$InvalidChargePolicy", cc=callContext) {
ChargePolicy.values.contains(ChargePolicy.withName(chargePolicy))
}
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodyCounterparty)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transactionRequestBodyCounterparty,
transDetailsSerialized,
chargePolicy,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext)
} yield (createdTransactionRequest, callContext)
}
case SIMPLE => {
for {
//For SAMPLE, we will create/get toCounterparty on site and set up the toAccount
transactionRequestBodySimple <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $SIMPLE json format", 400, callContext) {
json.extract[TransactionRequestBodySimpleJsonV400]
}
(toCounterparty, callContext) <- NewStyle.function.getOrCreateCounterparty(
name = transactionRequestBodySimple.to.name,
description = transactionRequestBodySimple.to.description,
currency = transactionRequestBodySimple.value.currency,
createdByUserId = u.userId,
thisBankId = bankId.value,
thisAccountId = accountId.value,
thisViewId = viewId.value,
otherBankRoutingScheme = transactionRequestBodySimple.to.other_bank_routing_scheme,
otherBankRoutingAddress = transactionRequestBodySimple.to.other_bank_routing_address,
otherBranchRoutingScheme = transactionRequestBodySimple.to.other_branch_routing_scheme,
otherBranchRoutingAddress = transactionRequestBodySimple.to.other_branch_routing_address,
otherAccountRoutingScheme = transactionRequestBodySimple.to.other_account_routing_scheme,
otherAccountRoutingAddress = transactionRequestBodySimple.to.other_account_routing_address,
otherAccountSecondaryRoutingScheme = transactionRequestBodySimple.to.other_account_secondary_routing_scheme,
otherAccountSecondaryRoutingAddress = transactionRequestBodySimple.to.other_account_secondary_routing_address,
callContext: Option[CallContext],
)
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
// Check we can send money to it.
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
toCounterparty.isBeneficiary
}
chargePolicy = transactionRequestBodySimple.charge_policy
_ <- Helper.booleanToFuture(s"$InvalidChargePolicy", cc=callContext) {
ChargePolicy.values.contains(ChargePolicy.withName(chargePolicy))
}
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodySimple)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transactionRequestBodySimple,
transDetailsSerialized,
chargePolicy,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext)
} yield (createdTransactionRequest, callContext)
}
case SEPA => {
for {
//For SEPA, Use the iban to find the toCounterparty and set up the toAccount
transDetailsSEPAJson <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $SEPA json format", 400, callContext) {
json.extract[TransactionRequestBodySEPAJsonV400]
}
toIban = transDetailsSEPAJson.to.iban
(toCounterparty, callContext) <- NewStyle.function.getCounterpartyByIbanAndBankAccountId(toIban, fromAccount.bankId, fromAccount.accountId, callContext)
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
toCounterparty.isBeneficiary
}
chargePolicy = transDetailsSEPAJson.charge_policy
_ <- Helper.booleanToFuture(s"$InvalidChargePolicy", cc=callContext) {
ChargePolicy.values.contains(ChargePolicy.withName(chargePolicy))
}
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transDetailsSEPAJson)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transDetailsSEPAJson,
transDetailsSerialized,
chargePolicy,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
transDetailsSEPAJson.reasons.map(_.map(_.transform)),
None,
callContext)
} yield (createdTransactionRequest, callContext)
}
case FREE_FORM => {
for {
transactionRequestBodyFreeForm <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $FREE_FORM json format", 400, callContext) {
json.extract[TransactionRequestBodyFreeFormJSON]
}
// Following lines: just transfer the details body, add Bank_Id and Account_Id in the Detail part. This is for persistence and 'answerTransactionRequestChallenge'
transactionRequestAccountJSON = TransactionRequestAccountJsonV140(bankId.value, accountId.value)
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodyFreeForm)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
fromAccount,
transactionRequestType,
transactionRequestBodyFreeForm,
transDetailsSerialized,
sharedChargePolicy.toString,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext)
} yield
(createdTransactionRequest, callContext)
}
} yield (createdTransactionRequest, callContext)
}
case ACCOUNT | SANDBOX_TAN => {
for {
transactionRequestBodySandboxTan <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $ACCOUNT json format", 400, callContext) {
json.extract[TransactionRequestBodySandBoxTanJSON]
}
toBankId = BankId(transactionRequestBodySandboxTan.to.bank_id)
toAccountId = AccountId(transactionRequestBodySandboxTan.to.account_id)
(toAccount, callContext) <- NewStyle.function.checkBankAccountExists(toBankId, toAccountId, callContext)
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodySandboxTan)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transactionRequestBodySandboxTan,
transDetailsSerialized,
sharedChargePolicy.toString,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"
} yield (createdTransactionRequest, callContext)
}
case ACCOUNT_OTP => {
for {
transactionRequestBodySandboxTan <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $ACCOUNT json format", 400, callContext) {
json.extract[TransactionRequestBodySandBoxTanJSON]
}
toBankId = BankId(transactionRequestBodySandboxTan.to.bank_id)
toAccountId = AccountId(transactionRequestBodySandboxTan.to.account_id)
(toAccount, callContext) <- NewStyle.function.checkBankAccountExists(toBankId, toAccountId, callContext)
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodySandboxTan)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transactionRequestBodySandboxTan,
transDetailsSerialized,
sharedChargePolicy.toString,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"
} yield (createdTransactionRequest, callContext)
}
case COUNTERPARTY => {
for {
//For COUNTERPARTY, Use the counterpartyId to find the toCounterparty and set up the toAccount
transactionRequestBodyCounterparty <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $COUNTERPARTY json format", 400, callContext) {
json.extract[TransactionRequestBodyCounterpartyJSON]
}
toCounterpartyId = transactionRequestBodyCounterparty.to.counterparty_id
(toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(toCounterpartyId), callContext)
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
// Check we can send money to it.
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
toCounterparty.isBeneficiary
}
chargePolicy = transactionRequestBodyCounterparty.charge_policy
_ <- Helper.booleanToFuture(s"$InvalidChargePolicy", cc=callContext) {
ChargePolicy.values.contains(ChargePolicy.withName(chargePolicy))
}
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodyCounterparty)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transactionRequestBodyCounterparty,
transDetailsSerialized,
chargePolicy,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext)
} yield (createdTransactionRequest, callContext)
}
case SIMPLE => {
for {
//For SAMPLE, we will create/get toCounterparty on site and set up the toAccount
transactionRequestBodySimple <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $SIMPLE json format", 400, callContext) {
json.extract[TransactionRequestBodySimpleJsonV400]
}
(toCounterparty, callContext) <- NewStyle.function.getOrCreateCounterparty(
name = transactionRequestBodySimple.to.name,
description = transactionRequestBodySimple.to.description,
currency = transactionRequestBodySimple.value.currency,
createdByUserId = u.userId,
thisBankId = bankId.value,
thisAccountId = accountId.value,
thisViewId = viewId.value,
otherBankRoutingScheme = transactionRequestBodySimple.to.other_bank_routing_scheme,
otherBankRoutingAddress = transactionRequestBodySimple.to.other_bank_routing_address,
otherBranchRoutingScheme = transactionRequestBodySimple.to.other_branch_routing_scheme,
otherBranchRoutingAddress = transactionRequestBodySimple.to.other_branch_routing_address,
otherAccountRoutingScheme = transactionRequestBodySimple.to.other_account_routing_scheme,
otherAccountRoutingAddress = transactionRequestBodySimple.to.other_account_routing_address,
otherAccountSecondaryRoutingScheme = transactionRequestBodySimple.to.other_account_secondary_routing_scheme,
otherAccountSecondaryRoutingAddress = transactionRequestBodySimple.to.other_account_secondary_routing_address,
callContext: Option[CallContext],
)
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
// Check we can send money to it.
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
toCounterparty.isBeneficiary
}
chargePolicy = transactionRequestBodySimple.charge_policy
_ <- Helper.booleanToFuture(s"$InvalidChargePolicy", cc=callContext) {
ChargePolicy.values.contains(ChargePolicy.withName(chargePolicy))
}
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodySimple)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transactionRequestBodySimple,
transDetailsSerialized,
chargePolicy,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext)
} yield (createdTransactionRequest, callContext)
}
case SEPA => {
for {
//For SEPA, Use the iban to find the toCounterparty and set up the toAccount
transDetailsSEPAJson <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $SEPA json format", 400, callContext) {
json.extract[TransactionRequestBodySEPAJsonV400]
}
toIban = transDetailsSEPAJson.to.iban
(toCounterparty, callContext) <- NewStyle.function.getCounterpartyByIbanAndBankAccountId(toIban, fromAccount.bankId, fromAccount.accountId, callContext)
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
toCounterparty.isBeneficiary
}
chargePolicy = transDetailsSEPAJson.charge_policy
_ <- Helper.booleanToFuture(s"$InvalidChargePolicy", cc=callContext) {
ChargePolicy.values.contains(ChargePolicy.withName(chargePolicy))
}
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transDetailsSEPAJson)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
toAccount,
transactionRequestType,
transDetailsSEPAJson,
transDetailsSerialized,
chargePolicy,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
transDetailsSEPAJson.reasons.map(_.map(_.transform)),
None,
callContext)
} yield (createdTransactionRequest, callContext)
}
case FREE_FORM => {
for {
transactionRequestBodyFreeForm <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $FREE_FORM json format", 400, callContext) {
json.extract[TransactionRequestBodyFreeFormJSON]
}
// Following lines: just transfer the details body, add Bank_Id and Account_Id in the Detail part. This is for persistence and 'answerTransactionRequestChallenge'
transactionRequestAccountJSON = TransactionRequestAccountJsonV140(bankId.value, accountId.value)
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
write(transactionRequestBodyFreeForm)(Serialization.formats(NoTypeHints))
}
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
viewId,
fromAccount,
fromAccount,
transactionRequestType,
transactionRequestBodyFreeForm,
transDetailsSerialized,
sharedChargePolicy.toString,
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
callContext)
} yield
(createdTransactionRequest, callContext)
}
(challenges, callContext) <- NewStyle.function.getChallengesByTransactionRequestId(createdTransactionRequest.id.value, callContext)
} yield {
(JSONFactory400.createTransactionRequestWithChargeJSON(createdTransactionRequest, challenges), HttpCode.`201`(callContext))
}
}
(challenges, callContext) <- NewStyle.function.getChallengesByTransactionRequestId(createdTransactionRequest.id.value, callContext)
} yield {
(JSONFactory400.createTransactionRequestWithChargeJSON(createdTransactionRequest, challenges), HttpCode.`201`(callContext))
}
}
lazy val createTransactionRequestAccount: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
"ACCOUNT" :: "transaction-requests" :: Nil JsonPost json -> _ =>
cc =>
val transactionRequestType = TransactionRequestType("ACCOUNT")
createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
}
lazy val createTransactionRequestAccountOtp: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
"ACCOUNT_OTP" :: "transaction-requests" :: Nil JsonPost json -> _ =>
cc =>
val transactionRequestType = TransactionRequestType("ACCOUNT_OTP")
createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
}
lazy val createTransactionRequestSepa: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
"SEPA" :: "transaction-requests" :: Nil JsonPost json -> _ =>
cc =>
val transactionRequestType = TransactionRequestType("SEPA")
createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
}
lazy val createTransactionRequestCounterparty: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
"COUNTERPARTY" :: "transaction-requests" :: Nil JsonPost json -> _ =>
cc =>
val transactionRequestType = TransactionRequestType("COUNTERPARTY")
createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
}
lazy val createTransactionRequestRefund: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
"REFUND" :: "transaction-requests" :: Nil JsonPost json -> _ =>
cc =>
val transactionRequestType = TransactionRequestType("REFUND")
createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
}
lazy val createTransactionRequestFreeForm: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
"FREE_FORM" :: "transaction-requests" :: Nil JsonPost json -> _ =>
cc =>
val transactionRequestType = TransactionRequestType("FREE_FORM")
createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
}
lazy val createTransactionRequestSimple: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
"SIMPLE" :: "transaction-requests" :: Nil JsonPost json -> _ =>
cc =>
val transactionRequestType = TransactionRequestType("SIMPLE")
createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
}
@ -8322,7 +8365,7 @@ trait APIMethods400 {
}
}
}
staticResourceDocs += ResourceDoc(
addConsentUser,
implementedInApiVersion,
@ -11471,8 +11514,7 @@ trait APIMethods400 {
EmptyBody,
atmsJsonV400,
List(
$UserNotLoggedIn,
InvalidJsonFormat,
$BankNotFound,
UnknownError
),
List(apiTagATM, apiTagNewStyle)
@ -12435,7 +12477,7 @@ trait APIMethods400 {
DynamicEndpointHelper.getRoles(dynamicEndpointInfo)
}
_ <- NewStyle.function.tryons(InvalidJsonFormat+"Can not generate OBP external Resource Docs", 400, cc.callContext) {
JSONFactory1_4_0.createResourceDocsJson(dynamicEndpointInfo.resourceDocs.toList, false)
JSONFactory1_4_0.createResourceDocsJson(dynamicEndpointInfo.resourceDocs.toList, false, None)
}
(dynamicEndpoint, callContext) <- NewStyle.function.createDynamicEndpoint(bankId, cc.userId, postedJson.swaggerString, cc.callContext)
_ <- NewStyle.function.tryons(InvalidJsonFormat+s"Can not grant these roles ${roles.toString} ", 400, cc.callContext) {

View File

@ -69,7 +69,6 @@ import scala.collection.immutable.List
import scala.math.BigDecimal
import scala.util.Try
case class CallLimitPostJsonV400(
from_date : Date,
to_date : Date,

View File

@ -51,7 +51,7 @@ object OBPAPI4_0_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
val version : ApiVersion = ApiVersion.v4_0_0
val versionStatus = "BLEEDING-EDGE" // TODO this should be a property of ApiVersion.
val versionStatus = "DRAFT" // TODO this should be a property of ApiVersion.
// Possible Endpoints from 4.0.0, exclude one endpoint use - method,exclude multiple endpoints use -- method,
// e.g getEndpoints(Implementations4_0_0) -- List(Implementations4_0_0.genericEndpoint, Implementations4_0_0.root)
@ -81,7 +81,7 @@ object OBPAPI4_0_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
// register v4.0.0 apis first, Make them available for use!
registerRoutes(routes, allResourceDocs, apiPrefix, true)
logger.info(s"version $version has been run! There are ${routes.length} routes.")
logger.info(s"version $version has been run! There are ${routes.length} routes, ${allResourceDocs.length} allResourceDocs.")
// specified response for OPTIONS request.
private val corsResponse: Box[LiftResponse] = Full{

View File

@ -5,28 +5,51 @@ import code.api.util.APIUtil._
import code.api.util.ApiRole.{CanCreateUserAuthContextUpdate, canCreateUserAuthContext, canGetUserAuthContext}
import code.api.util.ApiTag._
import code.api.util.ErrorMessages._
import code.api.util.{ApiRole, NewStyle}
import code.api.util.{APIUtil, ApiRole, Consent, NewStyle}
import code.api.util.NewStyle.HttpCode
import code.api.v3_1_0.{PostUserAuthContextJson, PostUserAuthContextUpdateJsonV310}
import code.api.v3_1_0.{PostConsentBodyCommonJson, PostConsentEmailJsonV310, PostConsentEntitlementJsonV310, PostConsentPhoneJsonV310, PostConsentViewJsonV310, PostUserAuthContextJson, PostUserAuthContextUpdateJsonV310}
import code.bankconnectors.Connector
import code.consent.{ConsentRequests, Consents}
import code.entitlement.Entitlement
import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{apply => _}
import code.util.Helper
import code.views.Views
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.model.{BankId, UserAuthContextUpdateStatus}
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.common.Full
import net.liftweb.common.{Full}
import net.liftweb.http.{Req}
import net.liftweb.http.rest.RestHelper
import net.liftweb.json
import net.liftweb.json.compactRender
import net.liftweb.util.Props
import scala.collection.immutable.{List, Nil}
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
import scala.util.Random
trait APIMethods500 {
self: RestHelper =>
val Implementations5_0_0 = new Implementations500()
protected trait TestHead {
/**
* Test to see if the request is a GET and expecting JSON in the response.
* The path and the Req instance are extracted.
*/
def unapply(r: Req): Option[(List[String], Req)] =
if (r.requestType.head_? && testResponse_?(r))
Some(r.path.partPath -> r) else None
def testResponse_?(r: Req): Boolean
}
lazy val JsonHead = new TestHead with JsonTest
class Implementations500 {
val implementedInApiVersion = ApiVersion.v5_0_0
@ -69,7 +92,7 @@ trait APIMethods500 {
json.extract[PostUserAuthContextJson]
}
(user, callContext) <- NewStyle.function.findByUserId(userId, callContext)
(userAuthContext, callContext) <- NewStyle.function.createUserAuthContext(user, postedData.key, postedData.value, callContext)
(userAuthContext, callContext) <- NewStyle.function.createUserAuthContext(user, postedData.key.trim, postedData.value.trim, callContext)
} yield {
(JSONFactory500.createUserAuthContextJson(userAuthContext), HttpCode.`201`(callContext))
}
@ -90,7 +113,7 @@ trait APIMethods500 {
|${authenticationRequiredMessage(true)}
|
|""",
emptyObjectJson,
EmptyBody,
userAuthContextJsonV500,
List(
UserNotLoggedIn,
@ -132,6 +155,7 @@ trait APIMethods500 {
userAuthContextUpdateJsonV500,
List(
UserNotLoggedIn,
$BankNotFound,
InvalidJsonFormat,
CreateUserAuthContextError,
UnknownError
@ -148,7 +172,6 @@ trait APIMethods500 {
_ <- Helper.booleanToFuture(failMsg = ConsumerHasMissingRoles + CanCreateUserAuthContextUpdate, cc=callContext) {
checkScope(bankId.value, getConsumerPrimaryKey(callContext), ApiRole.canCreateUserAuthContextUpdate)
}
(_, callContext) <- NewStyle.function.getBank(bankId, callContext)
_ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){
List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod)
}
@ -156,7 +179,7 @@ trait APIMethods500 {
postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
json.extract[PostUserAuthContextJson]
}
(userAuthContextUpdate, callContext) <- NewStyle.function.validateUserAuthContextUpdateRequest(bankId.value, user.userId, postedData.key, postedData.value, scaMethod, callContext)
(userAuthContextUpdate, callContext) <- NewStyle.function.validateUserAuthContextUpdateRequest(bankId.value, user.userId, postedData.key.trim, postedData.value.trim, scaMethod, callContext)
} yield {
(JSONFactory500.createUserAuthContextUpdateJson(userAuthContextUpdate), HttpCode.`201`(callContext))
@ -170,15 +193,15 @@ trait APIMethods500 {
nameOf(answerUserAuthContextUpdateChallenge),
"POST",
"/banks/BANK_ID/users/current/auth-context-updates/AUTH_CONTEXT_UPDATE_ID/challenge",
"Answer Auth Context Update Challenge",
"Answer User Auth Context Update Challenge",
s"""
|Answer Auth Context Update Challenge.
|Answer User Auth Context Update Challenge.
|""",
postUserAuthContextUpdateJsonV310,
userAuthContextUpdateJsonV500,
List(
UserNotLoggedIn,
BankNotFound,
$BankNotFound,
InvalidJsonFormat,
InvalidConnectorResponse,
UnknownError
@ -201,8 +224,8 @@ trait APIMethods500 {
case status if status == UserAuthContextUpdateStatus.ACCEPTED.toString =>
NewStyle.function.createUserAuthContext(
user,
userAuthContextUpdate.key,
userAuthContextUpdate.value,
userAuthContextUpdate.key.trim,
userAuthContextUpdate.value.trim,
callContext).map(x => (Some(x._1), x._2))
case _ =>
Future((None, callContext))
@ -224,7 +247,373 @@ trait APIMethods500 {
}
}
}
staticResourceDocs += ResourceDoc(
createConsentRequest,
implementedInApiVersion,
nameOf(createConsentRequest),
"POST",
"/consumer/consent-requests",
"Create Consent Request",
s"""""",
postConsentRequestJsonV500,
consentRequestResponseJson,
List(
$BankNotFound,
InvalidJsonFormat,
ConsentMaxTTL,
UnknownError
),
apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: apiTagNewStyle :: Nil
)
lazy val createConsentRequest : OBPEndpoint = {
case "consumer" :: "consent-requests" :: Nil JsonPost json -> _ => {
cc =>
for {
(_, callContext) <- applicationAccess(cc)
_ <- passesPsd2Aisp(callContext)
failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentBodyCommonJson "
consentJson: PostConsentRequestJsonV500 <- NewStyle.function.tryons(failMsg, 400, callContext) {
json.extract[PostConsentRequestJsonV500]
}
maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty="consents.max_time_to_live", defaultValue=3600)
_ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc=callContext){
consentJson.time_to_live match {
case Some(ttl) => ttl <= maxTimeToLive
case _ => true
}
}
createdConsentRequest <- Future(ConsentRequests.consentRequestProvider.vend.createConsentRequest(
callContext.flatMap(_.consumer),
Some(compactRender(json))
)) map {
i => connectorEmptyResponse(i, callContext)
}
} yield {
(
ConsentRequestResponseJson(
createdConsentRequest.consentRequestId,
net.liftweb.json.parse(createdConsentRequest.payload),
createdConsentRequest.consumerId,
),
HttpCode.`201`(callContext)
)
}
}
}
staticResourceDocs += ResourceDoc(
getConsentRequest,
implementedInApiVersion,
nameOf(getConsentRequest),
"GET",
"/consumer/consent-requests/CONSENT_REQUEST_ID",
"Get Consent Request",
s"""""",
EmptyBody,
consentRequestResponseJson,
List(
$BankNotFound,
ConsentRequestNotFound,
UnknownError
),
apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: apiTagNewStyle :: Nil
)
lazy val getConsentRequest : OBPEndpoint = {
case "consumer" :: "consent-requests" :: consentRequestId :: Nil JsonGet _ => {
cc =>
for {
(_, callContext) <- applicationAccess(cc)
_ <- passesPsd2Aisp(callContext)
createdConsentRequest <- Future(ConsentRequests.consentRequestProvider.vend.getConsentRequestById(
consentRequestId
)) map {
i => unboxFullOrFail(i,callContext, ConsentRequestNotFound)
}
} yield {
(ConsentRequestResponseJson(
consent_request_id = createdConsentRequest.consentRequestId,
payload = json.parse(createdConsentRequest.payload),
consumer_id = createdConsentRequest.consumerId
),
HttpCode.`200`(callContext)
)
}
}
}
staticResourceDocs += ResourceDoc(
getConsentByConsentRequestId,
implementedInApiVersion,
nameOf(getConsentByConsentRequestId),
"GET",
"/consumer/consent-requests/CONSENT_REQUEST_ID/consents",
"Get Consent By Consent Request Id",
s"""
|
|This endpoint gets the Consent By consent request id.
|
|${authenticationRequiredMessage(true)}
|
""".stripMargin,
EmptyBody,
consentJsonV500,
List(
$UserNotLoggedIn,
UnknownError
),
List(apiTagConsent, apiTagPSD2AIS, apiTagPsd2, apiTagNewStyle))
lazy val getConsentByConsentRequestId: OBPEndpoint = {
case "consumer" :: "consent-requests" :: consentRequestId :: "consents" :: Nil JsonGet _ => {
cc =>
for {
(_, callContext) <- applicationAccess(cc)
consent<- Future { Consents.consentProvider.vend.getConsentByConsentRequestId(consentRequestId)} map {
unboxFullOrFail(_, callContext, ConsentRequestNotFound)
}
} yield {
(
ConsentJsonV500(
consent.consentId,
consent.jsonWebToken,
consent.status,
Some(consent.consentRequestId)
),
HttpCode.`200`(cc)
)
}
}
}
staticResourceDocs += ResourceDoc(
createConsentByConsentRequestIdEmail,
implementedInApiVersion,
nameOf(createConsentByConsentRequestIdEmail),
"POST",
"/consumer/consent-requests/CONSENT_REQUEST_ID/EMAIL/consents",
"Create Consent By Request Id(EMAIL)",
s"""
|
|This endpoint starts the process of creating a Consent by consent request id.
|
|""",
EmptyBody,
consentJsonV500,
List(
UserNotLoggedIn,
BankNotFound,
InvalidJsonFormat,
ConsentAllowedScaMethods,
RolesAllowedInConsent,
ViewsAllowedInConsent,
ConsumerNotFoundByConsumerId,
ConsumerIsDisabled,
InvalidConnectorResponse,
UnknownError
),
apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 :: apiTagNewStyle :: Nil)
staticResourceDocs += ResourceDoc(
createConsentByConsentRequestIdSms,
implementedInApiVersion,
nameOf(createConsentByConsentRequestIdSms),
"POST",
"/consumer/consent-requests/CONSENT_REQUEST_ID/SMS/consents",
"Create Consent By Request Id (SMS)",
s"""
|
|This endpoint starts the process of creating a Consent.
|
|""",
EmptyBody,
consentJsonV500,
List(
UserNotLoggedIn,
$BankNotFound,
InvalidJsonFormat,
ConsentAllowedScaMethods,
RolesAllowedInConsent,
ViewsAllowedInConsent,
ConsumerNotFoundByConsumerId,
ConsumerIsDisabled,
MissingPropsValueAtThisInstance,
SmsServerNotResponding,
InvalidConnectorResponse,
UnknownError
),
apiTagConsent :: apiTagPSD2AIS :: apiTagPsd2 ::apiTagNewStyle :: Nil)
lazy val createConsentByConsentRequestIdEmail = createConsentByConsentRequestId
lazy val createConsentByConsentRequestIdSms = createConsentByConsentRequestId
lazy val createConsentByConsentRequestId : OBPEndpoint = {
case "consumer" :: "consent-requests":: consentRequestId :: scaMethod :: "consents" :: Nil JsonPost _ -> _ => {
cc =>
for {
(Full(user), callContext) <- authenticatedAccess(cc)
createdConsentRequest <- Future(ConsentRequests.consentRequestProvider.vend.getConsentRequestById(
consentRequestId
)) map {
i => unboxFullOrFail(i,callContext, ConsentRequestNotFound)
}
_ <- Helper.booleanToFuture(ConsentRequestAlreadyUsed, cc=callContext){
Consents.consentProvider.vend.getConsentByConsentRequestId(consentRequestId).isEmpty
}
_ <- Helper.booleanToFuture(ConsentAllowedScaMethods, cc=callContext){
List(StrongCustomerAuthentication.SMS.toString(), StrongCustomerAuthentication.EMAIL.toString()).exists(_ == scaMethod)
}
failMsg = s"$InvalidJsonFormat The Json body should be the $PostConsentBodyCommonJson "
consentRequestJson <- NewStyle.function.tryons(failMsg, 400, callContext) {
json.parse(createdConsentRequest.payload).extract[PostConsentRequestJsonV500]
}
maxTimeToLive = APIUtil.getPropsAsIntValue(nameOfProperty="consents.max_time_to_live", defaultValue=3600)
_ <- Helper.booleanToFuture(s"$ConsentMaxTTL ($maxTimeToLive)", cc=callContext){
consentRequestJson.time_to_live match {
case Some(ttl) => ttl <= maxTimeToLive
case _ => true
}
}
requestedEntitlements = consentRequestJson.entitlements.getOrElse(Nil)
myEntitlements <- Entitlement.entitlement.vend.getEntitlementsByUserIdFuture(user.userId)
_ <- Helper.booleanToFuture(RolesAllowedInConsent, cc=callContext){
requestedEntitlements.forall(
re => myEntitlements.getOrElse(Nil).exists(
e => e.roleName == re.role_name && e.bankId == re.bank_id
)
)
}
postConsentViewJsons <- Future.sequence(
consentRequestJson.account_access.map(
access =>
NewStyle.function.getBankAccountByRouting(None,access.account_routing.scheme, access.account_routing.address, cc.callContext)
.map(result =>PostConsentViewJsonV310(
result._1.bankId.value,
result._1.accountId.value,
access.view_id
))
)
)
(_, assignedViews) <- Future(Views.views.vend.privateViewsUserCanAccess(user))
_ <- Helper.booleanToFuture(ViewsAllowedInConsent, cc=callContext){
postConsentViewJsons.forall(
rv => assignedViews.exists{
e =>
e.view_id == rv.view_id &&
e.bank_id == rv.bank_id &&
e.account_id == rv.account_id
}
)
}
(consumerId, applicationText) <- consentRequestJson.consumer_id match {
case Some(id) => NewStyle.function.checkConsumerByConsumerId(id, callContext) map {
c => (Some(c.consumerId.get), c.description)
}
case None => Future(None, "Any application")
}
challengeAnswer = Props.mode match {
case Props.RunModes.Test => Consent.challengeAnswerAtTestEnvironment
case _ => Random.nextInt(99999999).toString()
}
createdConsent <- Future(Consents.consentProvider.vend.createObpConsent(user, challengeAnswer, Some(consentRequestId))) map {
i => connectorEmptyResponse(i, callContext)
}
postConsentBodyCommonJson = PostConsentBodyCommonJson(
everything = consentRequestJson.everything,
views = postConsentViewJsons,
entitlements = consentRequestJson.entitlements.getOrElse(Nil),
consumer_id = consentRequestJson.consumer_id,
consent_request_id = Some(consentRequestId),
valid_from = consentRequestJson.valid_from,
time_to_live = consentRequestJson.time_to_live,
)
consentJWT = Consent.createConsentJWT(
user,
postConsentBodyCommonJson,
createdConsent.secret,
createdConsent.consentId,
consumerId,
postConsentBodyCommonJson.valid_from,
postConsentBodyCommonJson.time_to_live.getOrElse(3600)
)
_ <- Future(Consents.consentProvider.vend.setJsonWebToken(createdConsent.consentId, consentJWT)) map {
i => connectorEmptyResponse(i, callContext)
}
challengeText = s"Your consent challenge : ${challengeAnswer}, Application: $applicationText"
_ <- scaMethod match {
case v if v == StrongCustomerAuthentication.EMAIL.toString => // Send the email
for{
failMsg <- Future {s"$InvalidJsonFormat The Json body should be the $PostConsentEmailJsonV310"}
consentScaEmail <- NewStyle.function.tryons(failMsg, 400, callContext) {
consentRequestJson.email.head
}
(Full(status), callContext) <- Connector.connector.vend.sendCustomerNotification(
StrongCustomerAuthentication.EMAIL,
consentScaEmail,
Some("OBP Consent Challenge"),
challengeText,
callContext
)
} yield Future{status}
case v if v == StrongCustomerAuthentication.SMS.toString => // Not implemented
for {
failMsg <- Future {
s"$InvalidJsonFormat The Json body should be the $PostConsentPhoneJsonV310"
}
consentScaPhoneNumber <- NewStyle.function.tryons(failMsg, 400, callContext) {
consentRequestJson.phone_number.head
}
(Full(status), callContext) <- Connector.connector.vend.sendCustomerNotification(
StrongCustomerAuthentication.SMS,
consentScaPhoneNumber,
None,
challengeText,
callContext
)
} yield Future{status}
case _ =>Future{"Success"}
}
} yield {
(ConsentJsonV500(createdConsent.consentId, consentJWT, createdConsent.status, Some(createdConsent.consentRequestId)), HttpCode.`201`(callContext))
}
}
}
staticResourceDocs += ResourceDoc(
headAtms,
implementedInApiVersion,
nameOf(headAtms),
"HEAD",
"/banks/BANK_ID/atms",
"Head Bank ATMS",
s"""Head Bank ATMS.""",
EmptyBody,
atmsJsonV400,
List(
$BankNotFound,
UnknownError
),
List(apiTagATM, apiTagNewStyle)
)
lazy val headAtms : OBPEndpoint = {
case "banks" :: BankId(bankId) :: "atms" :: Nil JsonHead _ => {
cc =>
for {
(_, callContext) <- getAtmsIsPublic match {
case false => authenticatedAccess(cc)
case true => anonymousAccess(cc)
}
} yield {
("", HttpCode.`200`(callContext))
}
}
}
}
}

View File

@ -26,9 +26,12 @@
*/
package code.api.v5_0_0
import com.openbankproject.commons.model.{UserAuthContext, UserAuthContextUpdate}
import code.api.v3_1_0.{PostConsentEntitlementJsonV310}
import com.openbankproject.commons.model.{AccountRoutingJsonV121, UserAuthContext, UserAuthContextUpdate}
import net.liftweb.json.JsonAST.JValue
import java.util.Date
import scala.collection.immutable.List
case class UserAuthContextJsonV500(
user_auth_context_id: String,
@ -52,6 +55,33 @@ case class UserAuthContextUpdateJsonV500(
consumer_id: String,
)
case class PostConsentRequestResponseJson(consentRequestId: String)
case class ConsentRequestResponseJson(
consent_request_id: String,
payload : JValue,
consumer_id : String
)
case class AccountAccessV500(
// bank_routing: Option[BankRoutingJsonV121],
// branch_routing: Option[BranchRoutingJsonV141],
account_routing: AccountRoutingJsonV121,
view_id: String
)
case class PostConsentRequestJsonV500(
everything: Boolean,
account_access: List[AccountAccessV500],
entitlements: Option[List[PostConsentEntitlementJsonV310]],
consumer_id: Option[String],
email: Option[String],
phone_number: Option[String],
valid_from: Option[Date],
time_to_live: Option[Long]
)
case class ConsentJsonV500(consent_id: String, jwt: String, status: String, consent_request_id: Option[String])
object JSONFactory500 {
def createUserAuthContextJson(userAuthContext: UserAuthContext): UserAuthContextJsonV500 = {

View File

@ -81,14 +81,13 @@ object OBPAPI5_0_0 extends OBPRestHelper
private val endpoints: List[OBPEndpoint] = OBPAPI4_0_0.routes ++ endpointsOf5_0_0
// Filter the possible endpoints by the disabled / enabled Props settings and add them together
val routes : List[OBPEndpoint] = Implementations4_0_0.root :: // For now we make this mandatory
getAllowedEndpoints(endpoints, allResourceDocs)
val routes : List[OBPEndpoint] = getAllowedEndpoints(endpoints, allResourceDocs)
// register v5.0.0 apis first, Make them available for use!
registerRoutes(routes, allResourceDocs, apiPrefix, true)
logger.info(s"version $version has been run! There are ${routes.length} routes.")
logger.info(s"version $version has been run! There are ${routes.length} routes, ${allResourceDocs.length} allResourceDocs.")
// specified response for OPTIONS request.
private val corsResponse: Box[LiftResponse] = Full{

View File

@ -37,7 +37,7 @@ object BankAttributeProvider extends BankAttributeProviderTrait {
attribute.BankId_(bankId.value)
.Name(name)
.Type(attributType.toString)
.Value(value)
.`Value`(value)
.IsActive(isActive.getOrElse(true))
.saveMe()
}
@ -50,7 +50,7 @@ object BankAttributeProvider extends BankAttributeProviderTrait {
.BankId_(bankId.value)
.Name(name)
.Type(attributType.toString())
.Value(value)
.`Value`(value)
.IsActive(isActive.getOrElse(true))
.saveMe()
}
@ -73,7 +73,7 @@ class BankAttribute extends BankAttributeTrait with LongKeyedMapper[BankAttribut
object BankAttributeId extends MappedUUID(this)
object Name extends MappedString(this, 50)
object Type extends MappedString(this, 50)
object Value extends MappedString(this, 255)
object `Value` extends MappedString(this, 255)
object IsActive extends MappedBoolean(this) {
override def defaultValue = true
}
@ -83,7 +83,7 @@ class BankAttribute extends BankAttributeTrait with LongKeyedMapper[BankAttribut
override def bankAttributeId: String = BankAttributeId.get
override def name: String = Name.get
override def attributeType: BankAttributeType.Value = BankAttributeType.withName(Type.get)
override def value: String = Value.get
override def value: String = `Value`.get
override def isActive: Option[Boolean] = if (IsActive.jdbcFriendly(IsActive.calcFieldName) == null) { None } else Some(IsActive.get)
}

View File

@ -10,6 +10,7 @@ import code.accountapplication.AccountApplicationX
import code.accountattribute.AccountAttributeX
import code.accountholders.{AccountHolders, MapperAccountHolders}
import code.api.BerlinGroup.{AuthenticationType, ScaStatus}
import code.api.Constant
import code.api.Constant.{INCOMING_SETTLEMENT_ACCOUNT_ID, OUTGOING_SETTLEMENT_ACCOUNT_ID}
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.attributedefinition.{AttributeDefinition, AttributeDefinitionDI}
@ -840,7 +841,7 @@ object LocalMappedConnector extends Connector with MdcLoggable {
}
private lazy val getDbConnectionParameters: (String, String, String) = {
val dbUrl = APIUtil.getPropsValue("db.url") openOr "jdbc:h2:mem:OBPTest;DB_CLOSE_DELAY=-1"
val dbUrl = APIUtil.getPropsValue("db.url") openOr Constant.h2DatabaseDefaultUrlValue
val username = dbUrl.split(";").filter(_.contains("user")).toList.headOption.map(_.split("=")(1))
val password = dbUrl.split(";").filter(_.contains("password")).toList.headOption.map(_.split("=")(1))
val dbUser = APIUtil.getPropsValue("db.user").orElse(username)

View File

@ -17,10 +17,11 @@ object Consents extends SimpleInjector {
trait ConsentProvider {
def getConsentByConsentId(consentId: String): Box[MappedConsent]
def getConsentByConsentRequestId(consentRequestId: String): Box[MappedConsent]
def updateConsentStatus(consentId: String, status: ConsentStatus): Box[MappedConsent]
def updateConsentUser(consentId: String, user: User): Box[MappedConsent]
def getConsentsByUser(userId: String): List[MappedConsent]
def createConsent(user: User, challenge: String): Box[MappedConsent]
def createObpConsent(user: User, challengeAnswer: String, consentRequestId:Option[String]): Box[MappedConsent]
def setJsonWebToken(consentId: String, jwt: String): Box[MappedConsent]
def revoke(consentId: String): Box[MappedConsent]
def checkAnswer(consentId: String, challenge: String): Box[MappedConsent]
@ -86,6 +87,8 @@ trait Consent {
* @return Consumer ID
*/
def consumerId: String
def consentRequestId: String
/**
* This field identifies the standard of API of a related consent

View File

@ -0,0 +1,31 @@
package code.consent
import code.model.Consumer
import com.openbankproject.commons.model.User
import net.liftweb.common.Box
import net.liftweb.util.SimpleInjector
object ConsentRequests extends SimpleInjector {
val consentRequestProvider = new Inject(buildOne _) {}
def buildOne: ConsentRequestProvider = MappedConsentRequestProvider
}
trait ConsentRequestProvider {
def getConsentRequestById(consentRequestId: String): Box[ConsentRequest]
def createConsentRequest(consumer: Option[Consumer], payload: Option[String]): Box[ConsentRequest]
}
trait ConsentRequestTrait {
def consentRequestId: String
def payload: String
def consumerId: String
}

View File

@ -0,0 +1,45 @@
package code.consent
import code.model.Consumer
import code.util.MappedUUID
import net.liftweb.common.Box
import net.liftweb.mapper._
import net.liftweb.util.Helpers.tryo
object MappedConsentRequestProvider extends ConsentRequestProvider {
override def getConsentRequestById(consentRequestId: String): Box[ConsentRequest] = {
ConsentRequest.find(
By(ConsentRequest.ConsentRequestId, consentRequestId)
)
}
override def createConsentRequest(consumer: Option[Consumer], payload: Option[String]): Box[ConsentRequest] ={
tryo {
ConsentRequest
.create
.ConsumerId(consumer.map(_.consumerId.get).getOrElse(null))
.Payload(payload.getOrElse(""))
.saveMe()
}}
}
class ConsentRequest extends ConsentRequestTrait with LongKeyedMapper[ConsentRequest] with IdPK with CreatedUpdated {
def getSingleton = ConsentRequest
//the following are the obp consent.
object ConsentRequestId extends MappedUUID(this)
object Payload extends MappedText(this)
object ConsumerId extends MappedUUID(this) {
override def defaultValue = null
}
override def consentRequestId: String = ConsentRequestId.get
override def payload: String = Payload.get
override def consumerId: String = ConsumerId.get
}
object ConsentRequest extends ConsentRequest with LongKeyedMetaMapper[ConsentRequest] {
override def dbIndexes: List[BaseIndex[ConsentRequest]] = UniqueIndex(ConsentRequestId) :: super.dbIndexes
}

View File

@ -20,6 +20,13 @@ object MappedConsentProvider extends ConsentProvider {
By(MappedConsent.mConsentId, consentId)
)
}
override def getConsentByConsentRequestId(consentRequestId: String): Box[MappedConsent] ={
MappedConsent.find(
By(MappedConsent.mConsentRequestId, consentRequestId)
)
}
override def updateConsentStatus(consentId: String, status: ConsentStatus): Box[MappedConsent] = {
MappedConsent.find(By(MappedConsent.mConsentId, consentId)) match {
case Full(consent) =>
@ -55,13 +62,14 @@ object MappedConsentProvider extends ConsentProvider {
override def getConsentsByUser(userId: String): List[MappedConsent] = {
MappedConsent.findAll(By(MappedConsent.mUserId, userId))
}
override def createConsent(user: User, challengeAnswer: String): Box[MappedConsent] = {
override def createObpConsent(user: User, challengeAnswer: String, consentRequestId:Option[String]): Box[MappedConsent] = {
tryo {
val salt = BCrypt.gensalt()
val challengeAnswerHashed = BCrypt.hashpw(challengeAnswer, salt).substring(0, 44)
MappedConsent
.create
.mUserId(user.userId)
.mConsentRequestId(consentRequestId.getOrElse(null))
.mChallenge(challengeAnswerHashed)
.mSalt(salt)
.mStatus(ConsentStatus.INITIATED.toString)
@ -234,6 +242,9 @@ class MappedConsent extends Consent with LongKeyedMapper[MappedConsent] with IdP
object mConsumerId extends MappedUUID(this) {
override def defaultValue = null
}
object mConsentRequestId extends MappedUUID(this) {
override def defaultValue = null
}
object mApiStandard extends MappedString(this, 50)
object mApiVersion extends MappedString(this, 50)
@ -262,6 +273,7 @@ class MappedConsent extends Consent with LongKeyedMapper[MappedConsent] with IdP
override def challenge: String = mChallenge.get
override def jsonWebToken: String = mJsonWebToken.get
override def consumerId: String = mConsumerId.get
override def consentRequestId: String = mConsentRequestId.get
override def apiStandard: String = mApiStandard.get
override def apiVersion: String = mApiVersion.get

View File

@ -11,11 +11,11 @@ class MappedConsentAuthContext extends ConsentAuthContext with LongKeyedMapper[M
object ConsentAuthContextId extends MappedUUID(this)
object ConsentId extends UUIDString(this)
object Key extends MappedString(this, 255)
object Value extends MappedString(this, 255)
object `Value` extends MappedString(this, 255)
override def consentId = ConsentId.get
override def key = Key.get
override def value = Value.get
override def value = `Value`.get
override def consentAuthContextId = ConsentAuthContextId.get
override def timeStamp = createdAt.get
}

View File

@ -19,7 +19,7 @@ object MappedConsentAuthContextProvider extends ConsentAuthContextProvider with
}
def createConsentAuthContextAkka(consentId: String, key: String, value: String): Box[MappedConsentAuthContext] =
tryo {
MappedConsentAuthContext.create.ConsentId(consentId).Key(key).Value(value).saveMe()
MappedConsentAuthContext.create.ConsentId(consentId).Key(key).`Value`(value).saveMe()
}
override def getConsentAuthContexts(consentId: String): Future[Box[List[MappedConsentAuthContext]]] = Future {
@ -50,11 +50,11 @@ object MappedConsentAuthContextProvider extends ConsentAuthContextProvider with
By(MappedConsentAuthContext.ConsentId, consentId),
By(MappedConsentAuthContext.Key, authContext.key)
).map( authContext =>
authContext.Key(authContext.key).Value(authContext.value).saveMe()
authContext.Key(authContext.key).`Value`(authContext.value).saveMe()
)
)
val created = create.map( authContext =>
MappedConsentAuthContext.create.ConsentId(consentId).Key(authContext.key).Value(authContext.value).saveMe()
MappedConsentAuthContext.create.ConsentId(consentId).Key(authContext.key).`Value`(authContext.value).saveMe()
)
tryo {
updated ::: created

View File

@ -1,13 +1,16 @@
package code.context
import code.api.util.ErrorMessages
import code.api.util.APIUtil.transactionRequestChallengeTtl
import code.api.util.{APIUtil, ErrorMessages}
import code.util.Helper.MdcLoggable
import com.openbankproject.commons.model.UserAuthContextUpdateStatus
import net.liftweb.common.{Box, Empty, Failure, Full}
import net.liftweb.mapper.By
import net.liftweb.util.Helpers.tryo
import com.openbankproject.commons.ExecutionContext.Implicits.global
import net.liftweb.util.Helpers
import scala.compat.Platform
import scala.concurrent.Future
object MappedUserAuthContextUpdateProvider extends UserAuthContextUpdateProvider with MdcLoggable {
@ -49,12 +52,21 @@ object MappedUserAuthContextUpdateProvider extends UserAuthContextUpdateProvider
override def checkAnswer(consentId: String, challenge: String): Future[Box[MappedUserAuthContextUpdate]] = Future {
MappedUserAuthContextUpdate.find(By(MappedUserAuthContextUpdate.mUserAuthContextUpdateId, consentId)) match {
case Full(consent) =>
consent.status match {
case value if value == UserAuthContextUpdateStatus.INITIATED.toString =>
val status = if (consent.challenge == challenge) UserAuthContextUpdateStatus.ACCEPTED.toString else UserAuthContextUpdateStatus.REJECTED.toString
tryo(consent.mStatus(status).saveMe())
case _ =>
Full(consent)
val createDateTime = consent.createdAt.get
val challengeTTL : Long = Helpers.seconds(APIUtil.userAuthContextUpdateRequestChallengeTtl)
val expiredDateTime: Long = createDateTime.getTime+challengeTTL
val currentTime: Long = Platform.currentTime
if(expiredDateTime > currentTime)
consent.status match {
case value if value == UserAuthContextUpdateStatus.INITIATED.toString =>
val status = if (consent.challenge == challenge) UserAuthContextUpdateStatus.ACCEPTED.toString else UserAuthContextUpdateStatus.REJECTED.toString
tryo(consent.mStatus(status).saveMe())
case _ =>
Full(consent)
}
else{
Failure(s"${ErrorMessages.OneTimePasswordExpired} Current expiration time is ${APIUtil.userAuthContextUpdateRequestChallengeTtl} seconds")
}
case Empty =>
Empty ?~! ErrorMessages.UserAuthContextUpdateNotFound

View File

@ -4,6 +4,7 @@ import java.sql.{PreparedStatement, Timestamp}
import java.util.Date
import java.util.UUID.randomUUID
import code.api.Constant
import code.api.cache.Caching
import code.api.util._
import code.model.MappedConsumersProvider
@ -65,7 +66,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
}
private lazy val getDbConnectionParameters: (String, String, String) = {
val dbUrl = APIUtil.getPropsValue("db.url") openOr "jdbc:h2:mem:OBPTest;DB_CLOSE_DELAY=-1"
val dbUrl = APIUtil.getPropsValue("db.url") openOr Constant.h2DatabaseDefaultUrlValue
val username = dbUrl.split(";").filter(_.contains("user")).toList.headOption.map(_.split("=")(1))
val password = dbUrl.split(";").filter(_.contains("password")).toList.headOption.map(_.split("=")(1))
val dbUser = APIUtil.getPropsValue("db.user").orElse(username)

View File

@ -716,7 +716,7 @@ object MappedNonceProvider extends NoncesProvider {
case None =>
}
value match {
case Some(v) => n.value(v)
case Some(v) => n.`value`(v)
case None =>
}
val nonce = n.saveMe()
@ -733,7 +733,7 @@ object MappedNonceProvider extends NoncesProvider {
timestamp: Date,
value: String): Long = {
Nonce.count(
By(Nonce.value, value),
By(Nonce.`value`, value),
By(Nonce.tokenKey, tokenKey),
By(Nonce.consumerkey, consumerKey),
By(Nonce.timestamp, timestamp)
@ -763,7 +763,7 @@ class Nonce extends LongKeyedMapper[Nonce] {
timestamp.get.getTime().toString()
}
}
object value extends MappedString(this,250)
object `value` extends MappedString(this,250)
}
object Nonce extends Nonce with LongKeyedMetaMapper[Nonce]{}

View File

@ -30,7 +30,7 @@ import code.api.util.CommonFunctions.validUri
import code.UserRefreshes.UserRefreshes
import code.accountholders.AccountHolders
import code.api.dynamic.endpoint.helper.DynamicEndpointHelper
import code.api.util.APIUtil.{hasAnOAuthHeader, logger, validatePasswordOnCreation, _}
import code.api.util.APIUtil._
import code.api.util.ErrorMessages._
import code.api.util._
import code.api.{APIFailure, Constant, DirectLogin, GatewayLogin, OAuthHandshake}
@ -43,7 +43,7 @@ import code.users.Users
import code.util.Helper
import code.util.Helper.MdcLoggable
import code.views.Views
import com.openbankproject.commons.model.{User, _}
import com.openbankproject.commons.model._
import net.liftweb.common._
import net.liftweb.http._
import net.liftweb.mapper._
@ -274,7 +274,7 @@ class AuthUser extends MegaProtoUser[AuthUser] with CreatedUpdated with MdcLogga
invalidMsg = Helper.i18n("please.enter.your.password")
S.error("authuser_password_repeat", Text(Helper.i18n("please.re-enter.your.password")))
case false =>
if (validatePasswordOnCreation(passwordValue))
if (fullPasswordValidation(passwordValue))
invalidPw = false
else {
invalidPw = true
@ -947,7 +947,7 @@ def restoreSomeSessions(): Unit = {
*/
override def login: NodeSeq = {
// This query parameter is specific to Hydra ORA login request
val loginChallenge = S.param("login_challenge").getOrElse("")
val loginChallenge: Box[String] = S.param("login_challenge").or(S.getSessionAttribute("login_challenge"))
def redirectUri(): String = {
loginRedirect.get match {
case Full(url) =>
@ -980,12 +980,16 @@ def restoreSomeSessions(): Unit = {
// If there is the query parameter login_challenge in a url we know it is tha Hydra request
// TODO Write standalone application for Login and Consent Request of Hydra as Identity Provider
integrateWithHydra match {
case true if !loginChallenge.isEmpty =>
val acceptLoginRequest = new AcceptLoginRequest
val adminApi: AdminApi = new AdminApi
acceptLoginRequest.setSubject(user.username.get)
val result = adminApi.acceptLoginRequest(loginChallenge, acceptLoginRequest)
S.redirectTo(result.getRedirectTo)
case true =>
if (loginChallenge.isEmpty == false) {
val acceptLoginRequest = new AcceptLoginRequest
val adminApi: AdminApi = new AdminApi
acceptLoginRequest.setSubject(user.username.get)
val result = adminApi.acceptLoginRequest(loginChallenge.getOrElse(""), acceptLoginRequest)
S.redirectTo(result.getRedirectTo)
} else {
S.redirectTo(redirect)
}
case false =>
S.redirectTo(redirect)
}

View File

@ -1,47 +1,47 @@
package code.opentok
import code.api.util.APIUtil
import com.opentok._
import com.opentok.exception.OpenTokException
object OpenTokUtil {
private var session: Session = null
def createOpenTok: OpenTok = {
// Set the following constants with the API key and API secret
// that you receive when you sign up to use the OpenTok API:
val apiKey: Int = APIUtil.getPropsValue("meeting.tokbox_api_key", "0000").toInt
val apiSecret: String = APIUtil.getPropsValue("meeting.tokbox_api_secret", "YOUR API SECRET")
val opentok: OpenTok = new OpenTok(apiKey, apiSecret)
return opentok
}
@throws[OpenTokException]
def getSession: Session = {
if (session == null) {
// A session that uses the OpenTok Media Router:
session = createOpenTok.createSession(new SessionProperties.Builder().mediaMode(MediaMode.ROUTED).build)
}
return session
}
@throws[OpenTokException]
def generateTokenForModerator(expireTimeInMinutes: Int): String = {
// Generate a token. Use the Role MODERATOR. Expire time is defined by parameter expireTimeInMinutes.
val token: String = session.generateToken(new TokenOptions.Builder().role(Role.MODERATOR).expireTime((System.currentTimeMillis / 1000L) + (expireTimeInMinutes * 60)).data // in expireTimeInMinutes
("name=Simon").build)
return token
}
@throws[OpenTokException]
def generateTokenForPublisher(expireTimeInMinutes: Int): String = {
// Generate a token. Use the Role PUBLISHER. Expire time is defined by parameter expireTimeInMinutes.
val token: String = session.generateToken(new TokenOptions.Builder().role(Role.PUBLISHER).expireTime((System.currentTimeMillis / 1000L) + (expireTimeInMinutes * 60)).data // in expireTimeInMinutes
("name=Simon").build)
return token
}
}
class OpenTokUtil() // Empty constructor
extends Exception {
}
//package code.opentok
//
//import code.api.util.APIUtil
//import com.opentok._
//import com.opentok.exception.OpenTokException
//
//object OpenTokUtil {
// private var session: Session = null
//
// def createOpenTok: OpenTok = {
// // Set the following constants with the API key and API secret
// // that you receive when you sign up to use the OpenTok API:
// val apiKey: Int = APIUtil.getPropsValue("meeting.tokbox_api_key", "0000").toInt
// val apiSecret: String = APIUtil.getPropsValue("meeting.tokbox_api_secret", "YOUR API SECRET")
// val opentok: OpenTok = new OpenTok(apiKey, apiSecret)
// return opentok
// }
//
// @throws[OpenTokException]
// def getSession: Session = {
// if (session == null) {
// // A session that uses the OpenTok Media Router:
// session = createOpenTok.createSession(new SessionProperties.Builder().mediaMode(MediaMode.ROUTED).build)
// }
// return session
// }
//
// @throws[OpenTokException]
// def generateTokenForModerator(expireTimeInMinutes: Int): String = {
// // Generate a token. Use the Role MODERATOR. Expire time is defined by parameter expireTimeInMinutes.
// val token: String = session.generateToken(new TokenOptions.Builder().role(Role.MODERATOR).expireTime((System.currentTimeMillis / 1000L) + (expireTimeInMinutes * 60)).data // in expireTimeInMinutes
// ("name=Simon").build)
// return token
// }
//
// @throws[OpenTokException]
// def generateTokenForPublisher(expireTimeInMinutes: Int): String = {
// // Generate a token. Use the Role PUBLISHER. Expire time is defined by parameter expireTimeInMinutes.
// val token: String = session.generateToken(new TokenOptions.Builder().role(Role.PUBLISHER).expireTime((System.currentTimeMillis / 1000L) + (expireTimeInMinutes * 60)).data // in expireTimeInMinutes
// ("name=Simon").build)
// return token
// }
//}
//
//class OpenTokUtil() // Empty constructor
// extends Exception {
//}

View File

@ -34,7 +34,11 @@ class RemotedataAccountHoldersActor extends Actor with ObpActorHelper with MdcLo
case cc.bulkDeleteAllAccountHolders() =>
logger.debug(s"bulkDeleteAllAccountHolders()")
sender ! (mapper.bulkDeleteAllAccountHolders())
sender ! (mapper.bulkDeleteAllAccountHolders())
case cc.deleteAccountHolder(user: User, bankAccountUID :BankIdAccountId) =>
logger.debug(s"deleteAccountHolder($user,$bankAccountUID)")
sender ! (mapper.deleteAccountHolder(user, bankAccountUID))
case message => logger.warn("[AKKA ACTOR ERROR - REQUEST NOT RECOGNIZED] " + message)
}

View File

@ -92,6 +92,17 @@ class RemotedataCounterpartiesActor extends Actor with ObpActorHelper with MdcLo
case cc.getCounterparties(thisBankId: BankId, thisAccountId: AccountId, viewId: ViewId) =>
logger.debug(s"getCounterparties($thisBankId)")
sender ! (mapper.getCounterparties(thisBankId, thisAccountId, viewId))
case cc.getCounterpartyByRoutings(otherBankRoutingScheme: String,
otherBankRoutingAddress: String,
otherBranchRoutingScheme: String,
otherBranchRoutingAddress: String,
otherAccountRoutingScheme: String,
otherAccountRoutingAddress: String) =>
logger.debug(s"getCounterpartyByRoutings($otherBankRoutingScheme,$otherBankRoutingAddress,$otherBranchRoutingScheme,$otherBranchRoutingAddress,$otherAccountRoutingScheme,$otherAccountRoutingAddress)")
sender ! (mapper.getCounterpartyByRoutings(otherBankRoutingScheme,
otherBankRoutingAddress, otherBranchRoutingScheme,
otherBranchRoutingAddress, otherAccountRoutingScheme, otherAccountRoutingAddress))
case cc.getCounterpartyByIban(iban: String) =>
logger.debug(s"getOrCreateMetadata($iban)")

View File

@ -1,6 +1,6 @@
package code.sandbox
import code.api.util.APIUtil.validatePasswordOnCreation
import code.api.util.APIUtil.fullPasswordValidation
import code.api.util.ErrorMessages
import code.model.dataAccess.{AuthUser, ResourceUser}
import code.users.Users
@ -38,7 +38,7 @@ trait CreateAuthUsers {
.validated(true)
val validationErrors = authUser.validate
if (!validatePasswordOnCreation(u.password)) Failure(ErrorMessages.InvalidStrongPasswordFormat)
if (!fullPasswordValidation(u.password)) Failure(ErrorMessages.InvalidStrongPasswordFormat)
else if(!validationErrors.isEmpty) Failure(s"Errors: ${validationErrors.map(_.msg)}")
else Full(asSaveable(authUser))
}

View File

@ -1,33 +1,26 @@
package code.search
import java.nio.charset.Charset
import dispatch.{Http, url}
import code.util.Helper.MdcLoggable
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import net.liftweb.http.{InMemoryResponse, JsonResponse, LiftResponse}
import net.liftweb.json.JsonAST._
import net.liftweb.util.Helpers
import net.liftweb.util.Props
import dispatch._
import Defaults._
import net.liftweb.json
import java.util.Date
import code.api.util.APIUtil
import code.api.util.ErrorMessages._
import com.sksamuel.elastic4s.ElasticsearchClientUri
import org.elasticsearch.common.settings.Settings
import com.sksamuel.elastic4s.http.HttpClient
import com.sksamuel.elastic4s.mappings.FieldType._
import com.sksamuel.elastic4s.http.ElasticDsl._
import dispatch.as.String.charset
import code.util.Helper.MdcLoggable
import com.sksamuel.elastic4s.http.JavaClient
import com.sksamuel.elastic4s.{ElasticClient, ElasticProperties}
import dispatch.Defaults._
import dispatch.{Http, url, _}
import net.liftweb.common.{Box, Empty, Failure, Full}
import net.liftweb.http.provider.HTTPCookie
import net.liftweb.http.{InMemoryResponse, JsonResponse, LiftResponse}
import net.liftweb.json
import net.liftweb.json.JsonAST
import net.liftweb.json.JsonAST._
import net.liftweb.util.Helpers
import org.elasticsearch.common.settings.Settings
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import scala.util.control.NoStackTrace
@ -250,22 +243,23 @@ class elasticsearchMetrics extends elasticsearch {
if (esIndex.contains(",")) throw new RuntimeException("Props error: es.metrics.index can not be a list")
var client:HttpClient = null
val props = ElasticProperties(s"http://$esHost:${esPortTCP.toInt}")
val client = ElasticClient(JavaClient(props))
// we must import the dsl
import com.sksamuel.elastic4s.ElasticDsl._
if (APIUtil.getPropsAsBoolValue("allow_elasticsearch", false) && APIUtil.getPropsAsBoolValue("allow_elasticsearch_metrics", false) ) {
val settings = Settings.builder().put("cluster.name", APIUtil.getPropsValue("es.cluster.name", "elasticsearch")).build()
client = HttpClient(ElasticsearchClientUri(esHost, esPortTCP.toInt))
try {
client.execute {
createIndex(esIndex).mappings(
mapping("request") as (
textField("userId"),
textField("url"),
dateField("date"),
textField("userName"),
textField("appName"),
textField("developerEmail"),
textField("correlationId")
createIndex(s"$esIndex/request").mapping(
properties (
textField("userId"),
textField("url"),
dateField("date"),
textField("userName"),
textField("appName"),
textField("developerEmail"),
textField("correlationId")
)
)
}
@ -278,8 +272,10 @@ class elasticsearchMetrics extends elasticsearch {
def indexMetric(userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, correlationId: String) {
if (APIUtil.getPropsAsBoolValue("allow_elasticsearch", false) && APIUtil.getPropsAsBoolValue("allow_elasticsearch_metrics", false) ) {
try {
// we must import the dsl
import com.sksamuel.elastic4s.ElasticDsl._
client.execute {
indexInto(esIndex / "request") fields (
indexInto(s"$esIndex/request") fields (
"userId" -> userId,
"url" -> url,
"date" -> date,
@ -304,77 +300,12 @@ class elasticsearchWarehouse extends elasticsearch {
override val esPortTCP = APIUtil.getPropsValue("es.warehouse.port.tcp","9300")
override val esPortHTTP = APIUtil.getPropsValue("es.warehouse.port.http","9200")
override val esIndex = APIUtil.getPropsValue("es.warehouse.index", "warehouse")
var client:HttpClient = null
val props = ElasticProperties(s"http://$esHost:${esPortTCP.toInt}")
var client: ElasticClient = null
if (APIUtil.getPropsAsBoolValue("allow_elasticsearch", false) && APIUtil.getPropsAsBoolValue("allow_elasticsearch_warehouse", false) ) {
val settings = Settings.builder().put("cluster.name", APIUtil.getPropsValue("es.cluster.name", "elasticsearch")).build()
client = HttpClient(ElasticsearchClientUri(esHost, esPortTCP.toInt))
client = ElasticClient(JavaClient(props))
}
}
/*
class elasticsearchOBP extends elasticsearch {
override val esHost = APIUtil.getPropsValue("es.obp.host","localhost")
override val esPortTCP = APIUtil.getPropsValue("es.obp.port.tcp","9300")
override val esPortHTTP = APIUtil.getPropsValue("es.obp.port.tcp","9200")
override val esIndex = APIUtil.getPropsValue("es.obp.index", "obp")
val accountIndex = "account_v1.2.1"
val transactionIndex = "transaction_v1.2.1"
var client:TcpClient = null
if (APIUtil.getPropsAsBoolValue("allow_elasticsearch", false) ) {
client = TcpClient.transport("elasticsearch://" + esHost + ":" + esPortTCP + ",")
client.execute {
create index accountIndex mappings (
"account" as (
"viewId" typed StringType,
"account" typed ObjectType
)
)
}
client.execute {
create index transactionIndex mappings (
"transaction" as (
"viewId" typed StringType,
"transaction" typed ObjectType
)
)
}
}
/*
Index objects in Elastic Search.
Use **the same** representations that we return in the REST API.
Use the name singular_object_name-version e.g. transaction-v1.2.1 for the index name / type
*/
// Index a Transaction
// Put into a index that has the viewId and version in the name.
def indexTransaction(viewId: String, transaction: TransactionJSON) {
if (APIUtil.getPropsAsBoolValue("allow_elasticsearch", false) ) {
client.execute {
index into transactionIndex / "transaction" fields (
"viewId" -> viewId,
"transaction" -> transaction
)
}
}
}
// Index an Account
// Put into a index that has the viewId and version in the name.
def indexAccount(viewId: String, account: AccountJSON) {
if (APIUtil.getPropsAsBoolValue("allow_elasticsearch", false) ) {
client.execute {
index into accountIndex / "account" fields (
"viewId" -> viewId,
"account" -> account
)
}
}
}
}
*/

View File

@ -60,6 +60,7 @@ class ConsumerRegistration extends MdcLoggable {
private object appType extends RequestVar("Unknown")
private object clientCertificateVar extends RequestVar("")
private object signingAlgVar extends RequestVar("")
private object oidcCheckboxVar extends RequestVar(false)
private object jwksUriVar extends RequestVar("")
private object jwksVar extends RequestVar("")
private object submitButtonDefenseFlag extends RequestVar("")
@ -113,6 +114,7 @@ class ConsumerRegistration extends MdcLoggable {
if(HydraUtil.integrateWithHydra) {
"#app-client_certificate" #> SHtml.textarea(clientCertificateVar, clientCertificateVar (_))&
"#app-request_uri" #> SHtml.text(requestUriVar, requestUriVar(_)) &
"#oidc_checkbox" #> SHtml.checkbox(oidcCheckboxVar, oidcCheckboxVar(_)) &
"#app-signing_alg" #> SHtml.select(signingAlgs, Box!! signingAlgVar.is, signingAlgVar(_)) &
"#app-jwks_uri" #> SHtml.text(jwksUriVar, jwksUriVar(_)) &
"#app-jwks" #> SHtml.textarea(jwksVar, jwksVar(_))
@ -135,12 +137,17 @@ class ConsumerRegistration extends MdcLoggable {
if(HydraUtil.integrateWithHydra) {
HydraUtil.createHydraClient(consumer, oAuth2Client => {
val signingAlg = signingAlgVar.is
if(oidcCheckboxVar.is == false) {
// TODO Set token_endpoint_auth_method in accordance to the Consumer.AppType value
// Consumer.AppType = Confidential => client_secret_post
// Consumer.AppType = Public => private_key_jwt
// Consumer.AppType = Unknown => private_key_jwt
oAuth2Client.setTokenEndpointAuthMethod(HydraUtil.hydraTokenEndpointAuthMethod)
} else {
oAuth2Client.setTokenEndpointAuthMethod(HydraUtil.clientSecretPost)
}
// TODO Set token_endpoint_auth_method in accordance to the Consumer.AppType value
// Consumer.AppType = Confidential => client_secret_post
// Consumer.AppType = Public => private_key_jwt
// Consumer.AppType = Unknown => private_key_jwt
oAuth2Client.setTokenEndpointAuthMethod(HydraUtil.hydraTokenEndpointAuthMethod)
oAuth2Client.setTokenEndpointAuthSigningAlg(signingAlg)
oAuth2Client.setRequestObjectSigningAlg(signingAlg)

View File

@ -44,6 +44,7 @@ import net.liftweb.util.PassThru
import scala.xml.{NodeSeq, XML}
import scala.io.Source
import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue
import net.liftweb.common.{Box, Full}
class WebUI extends MdcLoggable{
@ -64,6 +65,27 @@ class WebUI extends MdcLoggable{
}
}
def currentPage = {
def removeLocale(s: Box[String]) = {
s.map(_.replaceAll("&locale=es_ES", "")
.replaceAll("&locale=en_EN", "")
.replaceAll("\\?locale=es_ES", "")
.replaceAll("\\?locale=en_EN", ""))
}
val page = Constant.HostName + removeLocale(S.uriAndQueryString).getOrElse("")
S.queryString.map(_.replaceAll("locale=es_ES", "").replaceAll("locale=en_EN", "")) match {
case Full(queryString) if queryString.isEmpty =>
"#es a [href]" #> scala.xml.Unparsed(s"${page}?locale=es_ES") &
"#en a [href]" #> scala.xml.Unparsed(s"${page}?locale=en_EN")
case Full(queryString) =>
"#es a [href]" #> scala.xml.Unparsed(s"${page}&locale=es_ES") &
"#en a [href]" #> scala.xml.Unparsed(s"${page}&locale=en_EN")
case _ =>
"#es a [href]" #> scala.xml.Unparsed(s"${page}?locale=es_ES") &
"#en a [href]" #> scala.xml.Unparsed(s"${page}?locale=en_EN")
}
}
// Cookie Consent button.

View File

@ -68,7 +68,7 @@ object MappedChallengeProvider extends ChallengeProvider {
expiredDateTime: Long = createDateTime.getTime+challengeTTL
currentTime: Long = Platform.currentTime
challenge <- if(currentAttemptCounterValue <3){
challenge <- if(currentAttemptCounterValue < APIUtil.allowedAnswerTransactionRequestChallengeAttempts){
if(expiredDateTime > currentTime) {
val currentHashedAnswer = BCrypt.hashpw(challengeAnswer, challenge.salt).substring(0, 44)
val expectedHashedAnswer = challenge.expectedAnswer

View File

@ -99,7 +99,7 @@ object MappedTransactionRequestAttributeProvider extends TransactionRequestAttri
.TransactionRequestId(transactionRequestId.value)
.Name(name)
.Type(attributeType.toString)
.Value(value)
.`Value`(value)
.saveMe()
}
case _ => Empty
@ -112,7 +112,7 @@ object MappedTransactionRequestAttributeProvider extends TransactionRequestAttri
.TransactionRequestId(transactionRequestId.value)
.Name(name)
.Type(attributeType.toString())
.Value(value)
.`Value`(value)
.saveMe()
}
}
@ -131,7 +131,7 @@ object MappedTransactionRequestAttributeProvider extends TransactionRequestAttri
.BankId(bankId.value)
.Name(transactionRequestAttribute.name)
.Type(transactionRequestAttribute.attributeType.toString())
.Value(transactionRequestAttribute.value)
.`Value`(transactionRequestAttribute.value)
.saveMe()
}
}

View File

@ -21,7 +21,7 @@ class TransactionRequestAttribute extends TransactionRequestAttributeTrait with
override def attributeType: TransactionRequestAttributeType.Value = TransactionRequestAttributeType.withName(Type.get)
override def value: String = Value.get
override def value: String = `Value`.get
object BankId extends UUIDString(this) // combination of this
@ -33,7 +33,7 @@ class TransactionRequestAttribute extends TransactionRequestAttributeTrait with
object Type extends MappedString(this, 50)
object Value extends MappedString(this, 255)
object `Value` extends MappedString(this, 255)
}

View File

@ -39,7 +39,7 @@ object MappedUserAttributeProvider extends UserAttributeProvider {
.UserId(userId)
.Name(name)
.Type(attributeType.toString)
.Value(value)
.`Value`(value)
.saveMe()
}
case _ => Empty
@ -51,7 +51,7 @@ object MappedUserAttributeProvider extends UserAttributeProvider {
.UserId(userId)
.Name(name)
.Type(attributeType.toString())
.Value(value)
.`Value`(value)
.saveMe()
}
}
@ -67,13 +67,13 @@ class UserAttribute extends UserAttributeTrait with LongKeyedMapper[UserAttribut
object UserId extends MappedUUID(this)
object Name extends MappedString(this, 50)
object Type extends MappedString(this, 50)
object Value extends MappedString(this, 255)
object `Value` extends MappedString(this, 255)
override def userAttributeId: String = UserAttributeId.get
override def userId: String = UserId.get
override def name: String = Name.get
override def attributeType: UserAttributeType.Value = UserAttributeType.withName(Type.get)
override def value: String = Value.get
override def value: String = `Value`.get
override def insertDate: Date = createdAt.get
}

View File

@ -1,6 +1,5 @@
package code.users
import cats.Now
import code.util.Helper.MdcLoggable
import net.liftweb.common.{Box, Full}
import net.liftweb.mapper.By

View File

@ -25,6 +25,8 @@ object HydraUtil extends MdcLoggable{
val mirrorConsumerInHydra = APIUtil.getPropsAsBoolValue("mirror_consumer_in_hydra", false)
val clientSecretPost = "client_secret_post"
val hydraTokenEndpointAuthMethod =
APIUtil.getPropsValue("hydra_token_endpoint_auth_method", "private_key_jwt")
@ -40,7 +42,7 @@ object HydraUtil extends MdcLoggable{
.openOrThrowException(s"If props $INTEGRATE_WITH_HYDRA is true, hydra_client_scope value should not be blank")
.trim.split("""\s*,\s*""").toList
private lazy val allConsents = hydraConsents.mkString("openid offline ", " ","")
private lazy val allConsents = hydraConsents.mkString("openid offline email profile ", " ","")
val grantTypes = ("authorization_code" :: "client_credentials" :: "refresh_token" :: "implicit" :: Nil).asJava

View File

@ -14,12 +14,12 @@ trait NewAttributeQueryTrait {
// TODO Should we rename this column to attributeName
private lazy val nameColumn = Name.dbColumnName
// TODO Should we rename this column to attributeValue
private lazy val valueColumn = Value.dbColumnName
private lazy val valueColumn = `Value`.dbColumnName
private lazy val parentIdColumn = ParentId.dbColumnName
private lazy val bankIdColumn = BankId.dbColumnName
val BankId: BaseMappedField
val Name: BaseMappedField
val Value: BaseMappedField
val `Value`: BaseMappedField
/**
* Attribute entity's parent id, for example: CustomerAttribute.customerId,
* need implemented in companion object

View File

@ -153,6 +153,10 @@ Berlin 13359, Germany
<span data-lift="Msg?id=consumer-registration-app-client_certificate-error"/>
</div>
</div>
<div class="form-group">
<input type="checkbox" class="form-check-input" id="oidc_checkbox">
<label class="marketing-info-label" for="oidc_checkbox">OpenID Connect Client</label>
</div>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-danger" aria-describedby="register-consumer-errors"/>

View File

@ -31,10 +31,12 @@ Berlin 13359, Germany
<div id="main-about" data-lift="WebUI.aboutBackground">
<div id="main-about-row" class="row">
<div id="main-about-box">
<h1 id="main-about-text" data-lift="WebUI.aboutText">Welcome to the Open Bank Project API Sandbox test instance!</h1>
<h1 id="main-about-text" data-lift="WebUI.aboutText"><lift:loc locid="welcome.to">Welcome to the Open Bank Project API Sandbox test instance!</lift:loc></h1>
<div id="main-about-buttons">
<a class="api-explorer-link btn btn-danger" data-lift="WebUI.apiExplorerLink" href="">View API Explorer</a>
<a id="sandbox-introduction-link" class="btn btn-default" data-lift="WebUI.sandboxIntroductionLink" href="">Introduction</a>
<a class="api-explorer-link btn btn-danger" data-lift="WebUI.apiExplorerLink" href="">
<lift:loc locid="view_api_explorer">View API Explorer</lift:loc></a>
<a id="sandbox-introduction-link" class="btn btn-default" data-lift="WebUI.sandboxIntroductionLink" href="">
<lift:loc locid="introduction">Introduction</lift:loc></a>
<!-- <a href="/consumer-registration" class="btn btn-default">Get API key</a>-->
<!-- <a class="sofi-link btn btn-default" data-lift="WebUI.sofiLink" href="">SOFIT</a>-->
<!-- <a id="sandbox-introduction-link" class="btn btn-default" data-lift="WebUI.sandboxIntroductionLink" href="">INTRODUCTION</a>-->
@ -46,7 +48,7 @@ Berlin 13359, Germany
<div id="main-get-started">
<h2 id="get-started-part">Get started</h2>
<h2 id="get-started-part"><lift:loc locid="get_started_title">Get started</lift:loc></h2>
<div class="row">
<div class="col-md-5 main-get-started-icon">
<img class="create-account" src="/media/images/create_account.png" width="237" height="237" alt="create account"/>
@ -55,10 +57,9 @@ Berlin 13359, Germany
<img class="item-1" src="/media/images/icons/item-1.png" alt="item-1"/>
</div>
<div class="col-xs-12 col-md-5 main-get-started-text">
<h3>Create an account</h3>
<p>First, create a free developer account on this sandbox and request a developer key. You will be asked
to submit basic information about your app at this stage. <a href="/user_mgt/sign_up">Register for
an account</a>.</p>
<h3><lift:loc locid="get_started_create_account_title">Create an account</lift:loc></h3>
<p><lift:loc locid="get_started_create_account">First, create a free developer account on this sandbox and request a developer key. You will be asked to submit basic information about your app at this stage.</lift:loc><a href="/user_mgt/sign_up"><lift:loc locid="register_for_an_account">Register for an account</lift:loc>
</a>.</p>
</div>
</div>
<div class="row">
@ -69,10 +70,10 @@ Berlin 13359, Germany
<img class="item-2" src="/media/images/icons/item-2.png" alt="item-2"/>
</div>
<div class="col-xs-12 col-md-5 main-get-started-text">
<h3>Connect your app</h3>
<p>Use our SDKs to connect your app to the Open Bank Project APIs. Youll need your developer key, which
<h3><lift:loc locid="get_started_connect_your_app_title">Connect your app</lift:loc></h3>
<p><lift:loc locid="get_started_connect_your_app">Use our SDKs to connect your app to the Open Bank Project APIs. Youll need your developer key, which
you should have from when you created your account. Check out all the available APIs on the API
Explorer, but make sure that youre using the correct base URL.</p>
Explorer, but make sure that youre using the correct base URL.</lift:loc></p>
</div>
</div>
<div class="row">
@ -83,16 +84,17 @@ Berlin 13359, Germany
<img class="item-3" src="/media/images/icons/item-3.png" alt="item-3"/>
</div>
<div class="col-xs-12 col-md-5 main-get-started-text">
<h3>Test your app using customer data</h3>
<h3><lift:loc locid="get_started_test_your_app_title">Test your app using customer data</lift:loc></h3>
<p>
Once your app is connected, you can test it using test customer credentials.
<lift:loc locid="Test_your_app_description">Once your app is connected, you can test it using test customer credentials.</lift:loc>
<a class="example_sandbox_credentials_link" data-lift="WebUI.exampleSandboxCredentialsLink"
href="https://github.com/OpenBankProject/OBP-API/wiki/">View sandbox customer log ons.</a>
href="https://github.com/OpenBankProject/OBP-API/wiki/"><lift:loc locid="get_started_test_your_app_sandbox_date">View sandbox customer log ons.</lift:loc></a>
</p>
</div>
</div>
<div class="btn btn-primary">
<a href="/consumer-registration">Get API key</a>
<a href="/consumer-registration"><lift:loc locid="get_api_key">Get API key</lift:loc></a>
</div>
<hr style="color: #D7D8D6; margin-top: 56px;margin-bottom: 72px;">
@ -110,15 +112,15 @@ Berlin 13359, Germany
<div id="main-apis">
<h2 id="explorer-apis">Explore APIs</h2>
<h2 id="explorer-apis"><lift:loc locid="explore_api_title">Explore APIs</lift:loc></h2>
<div class="row">
<a class="api-explorer-link" data-lift="WebUI.apiExplorerLink?tags=Account,Card" href="">
<div class="col-xs-12 col-sm-1 col-lg-1 main-apis-icon">
<img class="icon-accounts" src="/media/images/icons/apis/icon-accounts.png" alt="accounts"/>
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Accounts<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="accounts chevron"/></h3>
<p>Access to accounts (XS21) and cards. Provide fine-grained access to guests (auditor, accountant or public).</p>
<h3><lift:loc locid="explore_api_accounts_title">Accounts</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="accounts chevron"/></h3>
<p><lift:loc locid="explore_api_accounts">Access to accounts (XS21) and cards. Provide fine-grained access to guests (auditor, accountant or public).</lift:loc></p>
</div>
</a>
@ -130,8 +132,8 @@ Berlin 13359, Germany
src="/media/images/icons/apis/icon-branches.png" alt="branches"/>
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Branches, ATMs and Products<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Branches chevron"/></h3>
<p>Access open data related to banks including branches and ATMs including geolocation and opening hours.</p>
<h3><lift:loc locid="explore_api_branches_title">Branches, ATMs and Products</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Branches chevron"/></h3>
<p><lift:loc locid="explore_api_branches">Access open data related to banks including branches and ATMs including geolocation and opening hours.</lift:loc></p>
</div>
</a>
@ -146,8 +148,8 @@ Berlin 13359, Germany
height="100" alt="transactions icon"/>
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Transactions<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Transactions chevron"/></h3>
<p>Access the transaction history and transaction metadata.</p>
<h3><lift:loc locid="explore_api_transactions_title">Transactions</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Transactions chevron"/></h3>
<p><lift:loc locid="explore_api_transactions">Access the transaction history and transaction metadata.</lift:loc></p>
</div>
</a>
@ -159,9 +161,9 @@ Berlin 13359, Germany
height="100" alt="metadata"/>
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Metadata<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Metadata chevron"/></h3>
<p>Enrich transactions and counterparties with metadata including geolocations, comments, pictures
and tags (e.g. category of spending).</p>
<h3><lift:loc locid="explore_api_metadata_title">Metadata</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Metadata chevron"/></h3>
<p><lift:loc locid="explore_api_metadata">Enrich transactions and counterparties with metadata including geolocations, comments, pictures
and tags (e.g. category of spending).</lift:loc></p>
</div>
</a>
@ -178,9 +180,9 @@ Berlin 13359, Germany
alt="counterparties"/>
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Counterparties<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Counterparties chevron"/></h3>
<p>Access the payers and payees of an account including metadata such as their aliases, labels,
logos and home pages.</p>
<h3><lift:loc locid="explore_api_counterparties_title">Metadata</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Counterparties chevron"/></h3>
<p><lift:loc locid="explore_api_counterparties">Access the payers and payees of an account including metadata such as their aliases, labels,
logos and home pages.</lift:loc></p>
</div>
</a>
@ -190,8 +192,8 @@ Berlin 13359, Germany
src="/media/images/icons/apis/icon-entitlements.png" alt="entitlements"/>
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Webhooks<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Webhooks chevron"/></h3>
<p>Call external web services based on Account events.</p>
<h3><lift:loc locid="explore_api_webhooks_title">Webhooks</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Webhooks chevron"/></h3>
<p><lift:loc locid="explore_api_webhooks">Call external web services based on Account events.</lift:loc></p>
</div>
</a>
</div>
@ -203,8 +205,8 @@ Berlin 13359, Germany
src="/media/images/icons/apis/icon-messages.png" alt="messages"/>
</div>
<div id ="customer-onboarding-and-kyc-div" class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Customer onboarding and KYC<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Customer onboarding and KYC chevron"/></h3>
<p>Perform user, customer and account creation. Manage Know Your Customer (KYC) documents, media and status. Create customer meetings and messages.</p>
<h3><lift:loc locid="explore_api_customer_title">Customer onboarding and KYC</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Customer onboarding and KYC chevron"/></h3>
<p><lift:loc locid="explore_api_customer">Perform user, customer and account creation. Manage Know Your Customer (KYC) documents, media and status. Create customer meetings and messages.</lift:loc></p>
</div>
</a>
@ -215,8 +217,8 @@ Berlin 13359, Germany
src="/media/images/icons/apis/icon-security.png" alt="security"/>
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text" id="api-roles-metrics-documentation">
<h3>API Roles, Metrics and Documentation<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="API Roles, Metrics and Documentation chevron"/></h3>
<p>Control access to endpoints, get API metrics and documentation.</p>
<h3><lift:loc locid="explore_api_roles_title">API Roles, Metrics and Documentation</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="API Roles, Metrics and Documentation chevron"/></h3>
<p><lift:loc locid="explore_api_roles">Control access to endpoints, get API metrics and documentation.</lift:loc></p>
</div>
</a>
@ -229,8 +231,8 @@ Berlin 13359, Germany
src="/media/images/icons/apis/icon-requests.png" alt="requests"/>
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Payments & Transfers<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Payments & Transfers chevron"/></h3>
<p>Initiate Transaction Requests (transfers and payments). View and confirm charges (as per PSD2). Answer strong customer authentication (SCA) challenges.</p>
<h3><lift:loc locid="explore_api_payments_title">Payments & Transfers</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="Payments & Transfers chevron"/></h3>
<p><lift:loc locid="explore_api_payments">Initiate Transaction Requests (transfers and payments). View and confirm charges (as per PSD2). Answer strong customer authentication (SCA) challenges.</lift:loc></p>
</div>
</a>
@ -239,8 +241,8 @@ Berlin 13359, Germany
<img class="icon-kyc" src="/media/images/icons/apis/icon-kyc.png" alt="kyc" />
</div>
<div class="col-xs-12 col-sm-5 col-lg-5 main-apis-text">
<h3>Search warehouse<img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="kyc chevron"/></h3>
<p>Perform advanced searches and statistics queries on the data warehouse.</p>
<h3><lift:loc locid="explore_api_warehouse_title">Search warehouse</lift:loc><img src="media/images/icons/chevron_right_thick_DB0011.svg" height="14" width="9.21" alt="kyc chevron"/></h3>
<p><lift:loc locid="explore_api_warehouse">Perform advanced searches and statistics queries on the data warehouse.</lift:loc></p>
</div>
</a>
</div>
@ -268,13 +270,13 @@ Berlin 13359, Germany
<div id="main-support">
<h2 id="technical-support">Support</h2>
<h2 id="technical-support"><lift:loc locid="support">Support</lift:loc></h2>
<div class="row">
<div class="col-xs-1" type="hidden"></div>
<div class="col-xs-2" type="hidden" id ="main-support_place_holder"></div>
<div class="main-support-item col-xs-3">
<img class="support-mail" src="/media/images/icons/support/email.svg" width="48" height="48" alt="mail"/>
<h3>Email</h3>
<h3><lift:loc locid="email.address">Email</lift:loc></h3>
<a id="webui-support-email" data-lift="WebUI.supportEmail" href="mailto:contact@openbankproject.com">contact@openbankproject.com</a>
</div>
@ -311,20 +313,23 @@ Berlin 13359, Germany
<div id="main-start">
<div id="main-start-row" class="row">
<div id="main-start_building" class="col-xs-12 col-sm-6">
<h2 name="get-started" data-lift="WebUI.getStartedText">Get started building your application</h2>
<h2 name="get-started" data-lift="WebUI.getStartedText"><lift:loc locid="get_started_building_your_application">Get started building your application</lift:loc></h2>
<div class="btn btn-default pull-left">
<a href="/consumer-registration">Get API key</a>
<a href="/consumer-registration">
<lift:loc locid="get_api_key">Get API key</lift:loc></a>
</div>
</div>
<div id="for-banks" name="for-banks" data-lift="WebUI.forBanks" class="col-xs-12 col-sm-6">
<h2>For banks</h2>
<h2><lift:loc locid="for_banks">For Banks</lift:loc></h2></h2>
<a class="api-manager-link btn btn-default pull-left"
data-lift="WebUI.apiManagerLink" href="">API Manager</a>
data-lift="WebUI.apiManagerLink" href="">
<lift:loc locid="api_manager">API Manager</lift:loc></a>
<a class="obp-cli-link btn btn-default pull-left" data-lift="WebUI.obpCliLink"
href="">OBP CLI</a>
<a class="api-tester-link btn btn-default pull-left"
data-lift="WebUI.apiTesterLink" href="">API Tester</a>
data-lift="WebUI.apiTesterLink" href="">
<lift:loc locid="api_tester">API Tester</lift:loc></a>
<a class="api-hola-link btn btn-default pull-left"
data-lift="WebUI.apiHolaLink" href="">Hola</a>
</div>

View File

@ -1,19 +1,19 @@
<div id="authorise" tabindex="-1">
<div class="login-error"><span data-lift="Msg?id=login&errorClass=error"/></div>
<div data-lift="Login.customiseLogin">
<h1 id="login-instruction-title">Log on to the Open Bank Project API</h1>
<h1 id="login-instruction-title"><lift:loc locid="logontext">Log on to the Open Bank Project API</lift:loc></h1>
<div id="login-special-instructions">Special Instructions</div>
<form class="login" action="/user_mgt/login" method="post">
<div class="form-group">
<p id="login-form-username">Username </p>
<p id="login-form-username"><lift:loc locid="username">Username</lift:loc></p>
<input class="form-control" id="username" type="text" name="username" tabindex="0" autofocus autocomplete="off" aria-label="Username" aria-describedby="login-form-username-error"/>
<div id = "login-username-error" class="hide">
<span data-lift="Msg?id=login-form-username-error"/>
</div>
</div>
<div class="form-group">
<p id="login-form-password">Password</p>
<p id="login-form-password"><lift:loc locid="passwordlog">Password</lift:loc></p>
<input class="form-control" id="password" type="password" name="password" tabindex="0" autocomplete="off" aria-label="Password" aria-describedby="login-form-password-error"/>
<div id = "login-password-error" class="hide">
<span data-lift="Msg?id=login-form-password-error"/>
@ -28,7 +28,7 @@
<!-- </div>-->
<div id="authorise-recover-password">
<a href="/user_mgt/lost_password" tabindex="0">Forgotten password?</a>
<a href="/user_mgt/lost_password" tabindex="0"><lift:loc locid="Forgotten_password">Forgotten password?</lift:loc></a>
</div>
<div class="row">
@ -38,14 +38,14 @@
</div>
</div>
<div class ="login-or"> or </div>
<div class ="login-or"> <lift:loc locid="or">or</lift:loc></div>
<hr>
<div class="row">
<span id="login-Register-text">Don't have an account? </span>
<a href="/user_mgt/sign_up" id="authorise-signup" class="btn btn-default pull-right authorise-button" tabindex="0">Register</a>
<span id="login-Register-text"><lift:loc locid="don't_have_account">Don't have an account?</lift:loc> </span>
<a href="/user_mgt/sign_up" id="authorise-signup" class="btn btn-default pull-right authorise-button" tabindex="0"><lift:loc locid="register">Register</lift:loc></a>
</div>
<div class ="login-or"> or Login with OpenID : </div>
<div class ="login-or">><lift:loc locid="or_login_with_openid">or Login with OpenID :</lift:loc> </div>
<hr>
<div data-lift="OpenIDConnectSnippet.showFirstButton">
<div data-lift="OpenidConnectInvoke.linkButtonFirstProvider">

View File

@ -139,6 +139,7 @@ Berlin 13359, Germany
<a href="/user_mgt/sign_up" class="navbar-btn" id ="register-link"><lift:loc locid="register">Register</lift:loc></a><a data-lift="Login.loggedOut" href="#" class="btn btn-danger login"><lift:loc locid="logon">Log on</lift:loc></a>
</p>
</li>
<li class="navitem" data-lift="Login.loggedIn" >
<!-- LOGGED IN -->
<p class="navbar-btn"><a href="/user-information"><span id="loggedIn-username">username</span></a><a href="#" class="btn btn-default logout">Log off</a></p>
@ -184,7 +185,8 @@ Berlin 13359, Germany
</li>
<li>
<div class="navitem" id="technical-faqs-anchor-nav">
<a class="navlink" id="technical-faqs-anchor" data-lift="WebUI.technicalFaqsAnchor" href="">Support</a>
<a class="navlink" id="technical-faqs-anchor" data-lift="WebUI.technicalFaqsAnchor" href="">
<lift:loc locid="support">Support</lift:loc></a>
</div>
</li>
<li>
@ -205,11 +207,12 @@ Berlin 13359, Germany
<div id="footer-div">
<ul>
<li>
<a class="termsAndConditions-link" data-lift="WebUI.termsAndConditions" href="">Terms and
Conditions</a>
<a class="termsAndConditions-link" data-lift="WebUI.termsAndConditions" href="">
<lift:loc locid="terms_conditions">Terms and Conditions</lift:loc></a>
</li>
<li>
<a class="privacy-policy-link" data-lift="WebUI.privacyPolicyLink" href="https://openbankproject.com/privacy-policy">Privacy Policy</a>
<a class="privacy-policy-link" data-lift="WebUI.privacyPolicyLink" href="https://openbankproject.com/privacy-policy">
<lift:loc locid="privacy_policy">Privacy Policy</lift:loc></a>
</li>
<li>
<a href="http://twitter.com/#!/OpenBankProject">Twitter</a>
@ -218,21 +221,30 @@ Berlin 13359, Germany
<a href="https://github.com/OpenBankProject/OBP-API/">Github</a>
</li>
<li>
<a class="api-documentation-link" data-lift="WebUI.apiDocumentationLink" href="">API
Documentation</a>
<a class="api-documentation-link" data-lift="WebUI.apiDocumentationLink" href="">
<lift:loc locid="api_documentation">API Documentation</lift:loc></a>
</li>
<li>
<a class="sofi-link" data-lift="WebUI.sofiLink" href="">Sofit</a>
</li>
<li>
<a href="/user_mgt/sign_up?after-signup=link-to-customer" class="navbar-btn" id ="register-link">On Board</a>
<a href="/user_mgt/sign_up?after-signup=link-to-customer" class="navbar-btn" id ="register-link">
<lift:loc locid="register">On Board</lift:loc></a>
</li>
<li>
<a class="api-link" data-lift="WebUI.apiLinkHuman" href="">This API Host</a>
<a class="api-link" data-lift="WebUI.apiLinkHuman" href="">
<lift:loc locid="api_host">This API Host</lift:loc></a>
</li>
</ul>
<br>
<div class="language-tag" data-lift="WebUI.currentPage">
<span><a href="#" >Language</a></span>
<span><a id="es" href="/" >ES</a></span>
<span><a href="/" >|</a></span>
<span><a id="en" href="/" >EN</a></span>
</div>
<div id="copyright">
<a href="http://openbankproject.com">Open Bank Project is &copy;2011 - <span id="copyright-year" data-lift="WebUI.currentYearText">2018</span> </a> <a href="http://tesobe.com">TESOBE and distributed under the AGPL and commercial licenses.</a>
<a href="http://openbankproject.com"><lift:loc locid="open_bank_project_is">Open Bank Project is &copy;2011 - </lift:loc> <span id="copyright-year" data-lift="WebUI.currentYearText">2018</span> </a> <a href="http://tesobe.com"><lift:loc locid="and_commercial_licenses">TESOBE and distributed under the AGPL and commercial licenses. </lift:loc></a>
</div>
</div>
</footer>

View File

@ -4,6 +4,7 @@ import code.api.BerlinGroup.ScaStatus
import code.api.berlin.group.v1_3.JSONFactory_BERLIN_GROUP_1_3.{CancellationJsonV13, InitiatePaymentResponseJson, StartPaymentAuthorisationJson}
import code.api.builder.PaymentInitiationServicePISApi.APIMethods_PaymentInitiationServicePISApi
import code.api.util.APIUtil.OAuth._
import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ErrorMessages.{AuthorisationNotFound, InvalidJsonFormat, NotPositiveAmount, _}
import code.model.dataAccess.{BankAccountRouting, MappedBankAccount}
import code.setup.{APIResponse, DefaultUsers}
@ -80,7 +81,7 @@ class PaymentInitiationServicePISApiTest extends BerlinGroupServerSetupV1_3 with
response.code should equal(400)
val error = s"${NotPositiveAmount} Current input is: '-1234'"
And("error should be " + error)
response.body.extract[ErrorMessage].message should equal (error)
response.body.extract[ErrorMessage].message contains extractErrorMessageCode(NotPositiveAmount) should be (true)
}
scenario("Successful case - small amount -- change the balance", BerlinGroupV1_3, PIS, initiatePayment) {
val accountsRoutingIban = BankAccountRouting.findAll(By(BankAccountRouting.AccountRoutingScheme, AccountRoutingScheme.IBAN.toString))

View File

@ -362,8 +362,9 @@ class OAuthTest extends ServerSetup {
Then("we set the valid username, valid password and try to login")
val verifier = getVerifier(requestToken.value, user2.username.get, user2Password)
org.scalameta.logger.elem(verifier)
Then("we should get a message: " + accountValidationError)
println(verifier)
verifier.contains(accountValidationError) should equal (true)
}
}

View File

@ -79,12 +79,12 @@ class JSONFactory1_4_0Test extends V140ServerSetup with DefaultUsers {
scenario("createResourceDocJson should work well, no exception is good enough") {
val resourceDoc: ResourceDoc = OBPAPI3_0_0.allResourceDocs(5)
val result: ResourceDocJson = JSONFactory1_4_0.createResourceDocJson(resourceDoc,false)
val result: ResourceDocJson = JSONFactory1_4_0.createResourceDocJson(resourceDoc,false, None)
}
scenario("createResourceDocsJson should work well, no exception is good enough") {
val resourceDoc: mutable.Seq[ResourceDoc] = OBPAPI3_0_0.allResourceDocs
val result = JSONFactory1_4_0.createResourceDocsJson(resourceDoc.toList, false)
val result = JSONFactory1_4_0.createResourceDocsJson(resourceDoc.toList, false, None)
}
scenario("createTypedBody should work well, no exception is good enough") {
@ -97,7 +97,7 @@ class JSONFactory1_4_0Test extends V140ServerSetup with DefaultUsers {
scenario("validate all the resouceDocs json schema, no exception is good enough") {
val resourceDocsRaw= OBPAPI3_0_0.allResourceDocs
val resourceDocs = JSONFactory1_4_0.createResourceDocsJson(resourceDocsRaw.toList,false)
val resourceDocs = JSONFactory1_4_0.createResourceDocsJson(resourceDocsRaw.toList,false, None)
for{
resouceDoc <- resourceDocs.resource_docs

View File

@ -3,6 +3,7 @@ package code.api.v2_0_0
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import com.openbankproject.commons.model.ErrorMessage
import code.api.util.APIUtil.OAuth._
import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ApiRole.CanGetEntitlementsForAnyUserAtAnyBank
import code.api.util.ErrorMessages.{UserHasMissingRoles, _}
import code.api.util.{ApiRole, ErrorMessages}
@ -74,7 +75,7 @@ class EntitlementTests extends V200ServerSetup with DefaultUsers {
Then("We should get a 403")
responsePost.code should equal(403)
responsePost.body.toString contains (UserHasMissingRoles) should be (true)
responsePost.body.toString contains (extractErrorMessageCode(UserHasMissingRoles)) should be (true)
Then("We grant the canCreateEntitlementAtOneBank role")
Entitlement.entitlement.vend.addEntitlement(testBankId1.value, resourceUser1.userId, ApiRole.canCreateEntitlementAtOneBank.toString)
@ -101,7 +102,7 @@ class EntitlementTests extends V200ServerSetup with DefaultUsers {
Then("We should get a 403")
responsePost.code should equal(403)
responsePost.body.toString contains (UserHasMissingRoles) should be (true)
responsePost.body.toString contains (extractErrorMessageCode(UserHasMissingRoles)) should be (true)
Then("We grant the canCreateEntitlementAtOneBank role")
Entitlement.entitlement.vend.addEntitlement("wrongbankId", resourceUser1.userId, ApiRole.canCreateEntitlementAtOneBank.toString)

View File

@ -1,6 +1,7 @@
package code.api.v2_2_0
import code.api.util.APIUtil.OAuth._
import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.{ApiRole, ErrorMessages}
import code.api.util.ErrorMessages.UserHasMissingRoles
import code.entitlement.Entitlement
@ -129,7 +130,7 @@ class AccountTest extends V220ServerSetup with DefaultUsers {
val responseWithNoRole = makePutRequest(requestPutNewAccountId, write(accountPutJSON2))
responseWithNoRole.code should equal(403)
responseWithNoRole.body.toString contains(s"$UserHasMissingRoles") should be (true)
responseWithNoRole.body.toString contains(extractErrorMessageCode(UserHasMissingRoles)) should be (true)
Then("We grant the roles and test it again")

View File

@ -5,6 +5,7 @@ import com.openbankproject.commons.model.{AccountRouting, AccountRoutingJsonV121
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.updateAccountRequestJsonV310
import code.api.util.APIUtil.OAuth._
import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn}
import code.api.util.ApiRole
import code.api.v2_0_0.BasicAccountJSON
@ -251,7 +252,7 @@ class AccountTest extends V310ServerSetup with DefaultUsers {
val responseWithNoRole = makePutRequest(request310WithNewAccountId, write(putCreateAccountOtherUserJsonV310))
Then("We should get a 403 and some error message")
responseWithNoRole.code should equal(403)
responseWithNoRole.body.toString contains(s"$UserHasMissingRoles") should be (true)
responseWithNoRole.body.toString contains(extractErrorMessageCode(UserHasMissingRoles)) should be (true)
Then("We grant the roles and test it again")

View File

@ -464,7 +464,7 @@ class AuthenticationTypeValidationTest extends V400ServerSetup {
| "to_currency_code": "USD",
| "conversion_value": 1.136305,
| "inverse_conversion_value": 0.8800454103431737,
| "effective_date": "2017-09-19T00:00:00Z"
| "effective_date": "1100-01-01T00:00:00Z"
|}
|""".stripMargin

View File

@ -3,6 +3,7 @@ package code.api.v4_0_0
import com.openbankproject.commons.model.ErrorMessage
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ApiRole.CanCreateDirectDebitAtOneBank
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.{NoViewPermission, UserHasMissingRoles, UserNotLoggedIn}
@ -45,7 +46,7 @@ class DirectDebitTest extends V400ServerSetup {
val response400 = makePostRequest(request400, write(postDirectDebitJsonV400))
Then("We should get a 400")
response400.code should equal(400)
response400.body.extract[ErrorMessage].message should startWith(NoViewPermission)
response400.body.extract[ErrorMessage].message contains extractErrorMessageCode(NoViewPermission) should be (true)
}
}

View File

@ -683,7 +683,7 @@ class ForceErrorValidationTest extends V400ServerSetup with PropsReset {
| "to_currency_code": "USD",
| "conversion_value": 1.136305,
| "inverse_conversion_value": 0.8800454103431737,
| "effective_date": "2017-09-19T00:00:00Z"
| "effective_date": "1100-01-01T00:00:00Z"
|}
|""".stripMargin

View File

@ -502,7 +502,7 @@ class JsonSchemaValidationTest extends V400ServerSetup {
| "to_currency_code":"USD",
| "conversion_value":1.136305,
| "inverse_conversion_value":0.8800454103431737,
| "effective_date":"2017-09-19T00:00:00Z"
| "effective_date":"1100-01-01T00:00:00Z"
| }],
| "required":["bank_id","from_currency_code","to_currency_code"],
| "properties":{
@ -530,7 +530,7 @@ class JsonSchemaValidationTest extends V400ServerSetup {
| "to_currency_code": "DEF",
| "conversion_value": 1.136305,
| "inverse_conversion_value": 0.8800454103431737,
| "effective_date": "2017-09-19T00:00:00Z"
| "effective_date": "1100-01-01T00:00:00Z"
|}
|""".stripMargin
@ -542,7 +542,7 @@ class JsonSchemaValidationTest extends V400ServerSetup {
| "to_currency_code": "USD",
| "conversion_value": 1.136305,
| "inverse_conversion_value": 0.8800454103431737,
| "effective_date": "2017-09-19T00:00:00Z"
| "effective_date": "1100-01-01T00:00:00Z"
|}
|""".stripMargin

View File

@ -3,6 +3,7 @@ package code.api.v4_0_0
import com.openbankproject.commons.model.ErrorMessage
import code.api.util.APIUtil.OAuth._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ApiRole.CanCreateStandingOrderAtOneBank
import com.openbankproject.commons.util.ApiVersion
import code.api.util.ErrorMessages.{NoViewPermission, UserHasMissingRoles, UserNotLoggedIn}
@ -45,7 +46,7 @@ class StandingOrderTest extends V400ServerSetup {
val response400 = makePostRequest(request400, write(postStandingOrderJsonV400))
Then("We should get a 400")
response400.code should equal(400)
response400.body.extract[ErrorMessage].message should startWith(NoViewPermission)
response400.body.extract[ErrorMessage].message contains extractErrorMessageCode(NoViewPermission) should be (true)
}
}

View File

@ -5,6 +5,7 @@ import code.api.ChargePolicy
import code.api.Constant._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.APIUtil.extractErrorMessageCode
import code.api.util.ApiRole.CanCreateAnyTransactionRequest
import code.api.util.ErrorMessages._
import code.api.util.{APIUtil, ErrorMessages}
@ -36,10 +37,15 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
* This is made possible by the scalatest maven plugin
*/
object VersionOfApi extends Tag(ApiVersion.v4_0_0.toString)
object ApiEndpoint1 extends Tag(nameOf(Implementations4_0_0.createTransactionRequest))
object ApiEndpoint2 extends Tag(nameOf(Implementations4_0_0.answerTransactionRequestChallenge))
object ApiEndpoint1 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestAccount))
object ApiEndpoint2 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestAccountOtp))
object ApiEndpoint3 extends Tag(nameOf(Implementations4_0_0.getTransactionRequest))
object ApiEndpoint4 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestSepa))
object ApiEndpoint5 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestCounterparty))
object ApiEndpoint6 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestRefund))
object ApiEndpoint7 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestFreeForm))
object ApiEndpoint8 extends Tag(nameOf(Implementations4_0_0.answerTransactionRequestChallenge))
object ApiEndpoint9 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestSimple))
def transactionCount(accounts: BankAccount*): Int = {
accounts.foldLeft(0)((accumulator, account) => {
@ -606,13 +612,14 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
feature("we can create transaction requests -- FREE_FORM") {
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
ignore("No challenge, No FX ", ApiEndpoint1) {}
ignore("No challenge, No FX ", ApiEndpoint7) {}
} else {
scenario("No challenge, No FX ", ApiEndpoint1) {
scenario("No challenge, No FX ", ApiEndpoint7) {
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
val helper = defaultSetup(FREE_FORM.toString)
addEntitlement(helper.bankId.value, resourceUser1.userId, CanCreateAnyTransactionRequest.toString)
Then("we call the 'V400 Create Transaction Request' endpoint")
val createTransactionRequestResponse = helper.makeCreateTransReqRequest
@ -636,12 +643,13 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
}
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
ignore("No challenge, With FX ", ApiEndpoint1) {}
ignore("No challenge, With FX ", ApiEndpoint7) {}
} else {
scenario("No challenge, With FX ", ApiEndpoint1) {
scenario("No challenge, With FX ", ApiEndpoint7) {
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
val helper = defaultSetup(FREE_FORM.toString)
addEntitlement(helper.bankId.value, resourceUser1.userId, CanCreateAnyTransactionRequest.toString)
And("We set the special conditions for different currencies")
val fromCurrency = "AED"
@ -676,11 +684,12 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
}
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
ignore("With challenge, No FX", ApiEndpoint1, ApiEndpoint2) {}
ignore("With challenge, No FX", ApiEndpoint7, ApiEndpoint2) {}
} else {
scenario("With challenge, No FX ", ApiEndpoint1, ApiEndpoint2) {
scenario("With challenge, No FX ", ApiEndpoint7, ApiEndpoint2) {
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
val helper = defaultSetup(FREE_FORM.toString)
addEntitlement(helper.bankId.value, resourceUser1.userId, CanCreateAnyTransactionRequest.toString)
And("We set the special conditions for different currencies")
val fromCurrency = "AED"
val toCurrency = "AED"
@ -722,11 +731,12 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
}
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
ignore("With challenge, With FX ", ApiEndpoint1, ApiEndpoint2) {}
ignore("With challenge, With FX ", ApiEndpoint7, ApiEndpoint2) {}
} else {
scenario("With challenge, With FX ", ApiEndpoint1, ApiEndpoint2) {
scenario("With challenge, With FX ", ApiEndpoint7, ApiEndpoint2) {
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
val helper = defaultSetup(FREE_FORM.toString)
addEntitlement(helper.bankId.value, resourceUser1.userId, CanCreateAnyTransactionRequest.toString)
And("We set the special conditions for different currencies")
val fromCurrency = "AED"
@ -1172,7 +1182,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
helper.setAnswerTransactionRequest(challengeId = challengeOfUser1.map(_.id).getOrElse(""))
And("we call the endpoint")
val ansReqResponseUser1 = helper.makeAnswerRequest
ansReqResponseUser1.body.extract[ErrorMessage].message should equal(NextChallengePending)
ansReqResponseUser1.body.extract[ErrorMessage].message contains extractErrorMessageCode(NextChallengePending) should be (true)
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
And("we prepare the parameters for it")
@ -1420,7 +1430,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
helper.setAnswerTransactionRequest(challengeId = challengeOfUser1.map(_.id).getOrElse(""))
And("we call the endpoint")
val ansReqResponseUser1 = helper.makeAnswerRequest
ansReqResponseUser1.body.extract[ErrorMessage].message should equal(NextChallengePending)
ansReqResponseUser1.body.extract[ErrorMessage].message contains extractErrorMessageCode(NextChallengePending) should be (true)
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
And("we prepare the parameters for it")

View File

@ -0,0 +1,75 @@
/**
Open Bank Project - API
Copyright (C) 2011-2019, TESOBE GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Email: contact@tesobe.com
TESOBE GmbH
Osloerstrasse 16/17
Berlin 13359, Germany
This product includes software developed at
TESOBE (http://www.tesobe.com/)
*/
package code.api.v5_0_0
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{postUserAuthContextJson, postUserAuthContextUpdateJsonV310}
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages._
import code.api.v3_1_0.CustomerJsonV310
import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.json.Serialization.write
import org.scalatest.Tag
import scala.language.postfixOps
class ATMTest extends V500ServerSetupAsync {
/**
* Test tags
* Example: To run tests with tag "getPermissions":
* mvn test -D tagsToInclude
*
* This is made possible by the scalatest maven plugin
*/
object VersionOfApi extends Tag(ApiVersion.v5_0_0.toString)
object ApiEndpoint1 extends Tag(nameOf(Implementations5_0_0.headAtms))
feature("Head Bank ATMS v5.0.0") {
scenario("We will call the Add endpoint properly", ApiEndpoint1, VersionOfApi) {
When("We make a request v5.0.0")
lazy val bankId = randomBankId
val request500 = (v5_0_0_Request / "banks" / bankId / "atms").HEAD
val response500 = makeHeadRequest(request500)
Then("We should get a 200")
response500.code should equal(200)
}
scenario("We will call the Add endpoint with wrong BankId", ApiEndpoint1, VersionOfApi) {
When("We make a request v5.0.0")
val request500 = (v5_0_0_Request / "banks" / "xx_non_existing_bank_id" / "atms").HEAD
val response500 = makeHeadRequest(request500)
Then("We should get a 404")
response500.code should equal(404)
}
}
}

View File

@ -0,0 +1,128 @@
/**
Open Bank Project - API
Copyright (C) 2011-2019, TESOBE GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Email: contact@tesobe.com
TESOBE GmbH
Osloerstrasse 16/17
Berlin 13359, Germany
This product includes software developed at
TESOBE (http://www.tesobe.com/)
*/
package code.api.v5_0_0
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
import code.api.util.APIUtil.OAuth._
import code.api.util.ApiRole._
import code.api.util.Consent
import code.api.util.ErrorMessages._
import code.api.v3_1_0.{PostConsentChallengeJsonV310, PostConsentEntitlementJsonV310, PostConsentViewJsonV310}
import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0
import code.consent.ConsentStatus
import code.entitlement.Entitlement
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.{AccountRoutingJsonV121, ErrorMessage}
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.json.Serialization.write
import org.scalatest.Tag
import scala.language.postfixOps
class ConsentRequestTest extends V500ServerSetupAsync {
/**
* Test tags
* Example: To run tests with tag "getPermissions":
* mvn test -D tagsToInclude
*
* This is made possible by the scalatest maven plugin
*/
object VersionOfApi extends Tag(ApiVersion.v5_0_0.toString)
object ApiEndpoint1 extends Tag(nameOf(Implementations5_0_0.createConsentRequest))
object ApiEndpoint2 extends Tag(nameOf(Implementations5_0_0.getConsentByConsentRequestId))
object ApiEndpoint3 extends Tag(nameOf(Implementations5_0_0.createConsentByConsentRequestId))
object ApiEndpoint4 extends Tag(nameOf(Implementations5_0_0.getConsentByConsentRequestId))
lazy val entitlements = List(PostConsentEntitlementJsonV310("", CanGetAnyUser.toString()))
lazy val accountAccess = List(AccountAccessV500(
account_routing = AccountRoutingJsonV121(
scheme = "AccountId",
address = testAccountId1.value), "owner"))
lazy val postConsentRequestJsonV310 = SwaggerDefinitionsJSON.postConsentRequestJsonV500
.copy(entitlements=Some(entitlements))
.copy(consumer_id=None)
.copy(account_access=accountAccess)
val createConsentRequestWithoutLoginUrl = (v5_0_0_Request / "consumer" / "consent-requests")
val createConsentRequestUrl = (v5_0_0_Request / "consumer"/ "consent-requests").POST<@(user1)
def getConsentRequestUrl(requestId:String) = (v5_0_0_Request / "consumer"/ "consent-requests"/requestId).GET<@(user1)
def createConsentByRequestIdUrl(requestId:String) = (v5_0_0_Request / "consumer"/ "consent-requests"/requestId/"EMAIL"/"consents").POST<@(user1)
def getConsentByRequestIdUrl(requestId:String) = (v5_0_0_Request / "consumer"/ "consent-requests"/requestId/"consents").GET<@(user1)
feature("Create/Get Consent Request v5.0.0") {
scenario("We will call the Create endpoint without a user credentials", ApiEndpoint1, VersionOfApi) {
When("We make a request v5.0.0")
val response500 = makePostRequest(createConsentRequestWithoutLoginUrl, write(postConsentRequestJsonV310))
Then("We should get a 401")
response500.code should equal(401)
response500.body.extract[ErrorMessage].message should equal (ApplicationNotIdentified)
}
scenario("We will call the Create, Get and Delete endpoints with user credentials ", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, VersionOfApi) {
When(s"We try $ApiEndpoint1 v5.0.0")
val createConsentResponse = makePostRequest(createConsentRequestUrl, write(postConsentRequestJsonV310))
Then("We should get a 201")
createConsentResponse.code should equal(201)
val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson]
val consentRequestId = createConsentRequestResponseJson.consent_request_id
When("We try to make the GET request v5.0.0")
val successGetRes = makeGetRequest(getConsentRequestUrl(consentRequestId))
Then("We should get a 200")
successGetRes.code should equal(200)
val getConsentRequestResponseJson = successGetRes.body.extract[ConsentRequestResponseJson]
getConsentRequestResponseJson.payload should not be("")
When("We try to make the GET request v5.0.0")
Then("We grant the role and test it again")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetAnyUser.toString)
val createConsentByRequestResponse = makePostRequest(createConsentByRequestIdUrl(consentRequestId), write(""))
Then("We should get a 200")
createConsentByRequestResponse.code should equal(201)
val consentId = createConsentByRequestResponse.body.extract[ConsentJsonV500].consent_id
val answerConsentChallengeRequest = (v5_0_0_Request / "banks" / testBankId1.value / "consents" / consentId / "challenge").POST <@ (user1)
val challenge = Consent.challengeAnswerAtTestEnvironment
val post = PostConsentChallengeJsonV310(answer = challenge)
val answerConsentChallengeResponse = makePostRequest(answerConsentChallengeRequest, write(post))
Then("We should get a 201")
answerConsentChallengeResponse.code should equal(201)
When("We try to make the GET request v5.0.0")
val getConsentByRequestResponse = makeGetRequest(getConsentByRequestIdUrl(consentRequestId))
Then("We should get a 200")
getConsentByRequestResponse.code should equal(200)
val getConsentByRequestResponseJson = getConsentByRequestResponse.body.extract[ConsentJsonV500]
getConsentByRequestResponseJson.consent_request_id.head should be(consentRequestId)
getConsentByRequestResponseJson.status should be(ConsentStatus.ACCEPTED.toString)
}
}
}

View File

@ -154,6 +154,7 @@ class UserAuthContextTest extends V500ServerSetupAsync {
When("We need to prepare the bankId first.")
val requestCreateCustomer = (v5_0_0_Request / "banks" / testBankId1.value / "customers").POST <@(user1)
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateCustomerAtAnyBank.toString)
val responseCustomer = makePostRequest(requestCreateCustomer, write(SwaggerDefinitionsJSON.postCustomerJsonV310))
Then("We should get a 201")
responseCustomer.code should equal(201)

View File

@ -1,10 +1,23 @@
package code.api.v5_0_0
import code.api.v4_0_0.BanksJson400
import code.setup._
import dispatch.Req
import scala.util.Random.nextInt
trait V500ServerSetupAsync extends ServerSetupWithTestDataAsync with DefaultUsers {
def v5_0_0_Request: Req = baseRequest / "obp" / "v5.0.0"
def randomBankId : String = {
def getBanksInfo : APIResponse = {
val request = v5_0_0_Request / "banks"
makeGetRequest(request)
}
val banksJson = getBanksInfo.body.extract[BanksJson400]
val randomPosition = nextInt(banksJson.banks.size)
val bank = banksJson.banks(randomPosition)
bank.id
}
}

View File

@ -105,7 +105,7 @@ class MappedAtmsProviderTest extends ServerSetup {
atms.size should equal(3)
And("they should be the licensed ones")
atms should equal (expectedAtms)
atms.sortBy(_.atmId.value) should equal (expectedAtms.sortBy(_.atmId.value))
}
scenario("We try to get atms for a bank that doesn't have any") {

View File

@ -104,7 +104,7 @@ class MappedBranchesProviderTest extends ServerSetup {
branches.size should equal(3)
And("they should be the licensed ones")
branches should equal (expectedBranches)
branches.sortBy(_.branchId.value) should equal (expectedBranches.sortBy(_.branchId.value))
}
scenario("We try to get branches for a bank that doesn't have any") {

View File

@ -93,7 +93,7 @@ class MappedProductsProviderTest extends ServerSetup {
products.size should equal(3)
And("they should be the licensed ones")
products should equal (expectedProducts)
products.sortBy(_.code.value) should equal (expectedProducts.sortBy(_.code.value))
}
scenario("We try to get Products for a bank that doesn't have any") {

View File

@ -71,8 +71,8 @@ trait LocalMappedConnectorTestSetup extends TestConnectorSetupWithStandardPermis
BankAccountRouting.create
.BankId(bankId.value)
.AccountId(accountId.value)
.AccountRoutingScheme(randomString(4))
.AccountRoutingAddress(randomString(4))
.AccountRoutingScheme("AccountId")
.AccountRoutingAddress(accountId.value)
.saveMe
MappedBankAccount.create
.bank(bankId.value)

View File

@ -258,6 +258,16 @@ trait SendServerRequests {
val jsonReq = createRequest(reqData)
getAPIResponse(jsonReq)
}
/**
* this method does a HEAD request given a URL
*/
def makeHeadRequest(req: Req, params: List[(String, String)] = Nil) : APIResponse = {
val extra_headers = Map.empty ++ params
val reqData = extractParamsAndHeaders(req.HEAD, "", "UTF-8", extra_headers)
val jsonReq = createRequest(reqData)
getAPIResponse(jsonReq)
}
/**
* this method does a GET request given a URL
*/

View File

@ -192,6 +192,7 @@ object DynamicEntityOperation extends OBPEnumeration[DynamicEntityOperation] {
sealed trait LanguageParam extends EnumValue
object LanguageParam extends OBPEnumeration[LanguageParam] {
object EN extends Value
object ES extends Value
object ZH extends Value
}

View File

@ -71,10 +71,10 @@ class JsonUtilsTest extends FlatSpec with Matchers {
val DateWithMsFormat = new SimpleDateFormat(DateWithMs)
val DateWithMsRollbackFormat = new SimpleDateFormat(DateWithMsRollback)
val DateWithDayExampleString: String = "2017-09-19"
val DateWithSecondsExampleString: String = "2017-09-19T02:31:05Z"
val DateWithMsExampleString: String = "2017-09-19T02:31:05.000Z"
val DateWithMsRollbackExampleString: String = "2017-09-19T02:31:05.000+0000"
val DateWithDayExampleString: String = "1100-01-01"
val DateWithSecondsExampleString: String = "1100-01-01T01:01:01Z"
val DateWithMsExampleString: String = "1100-01-01T01:01:01.000Z"
val DateWithMsRollbackExampleString: String = "1100-01-01T01:01:01.000+0000"
val DateWithDayExampleObject = DateWithDayFormat.parse(DateWithDayExampleString)

View File

@ -12,13 +12,13 @@
<properties>
<scala.version>2.12</scala.version>
<scala.compiler>2.12.10</scala.compiler>
<akka.version>2.5.19</akka.version>
<akka-streams-kafka.version>0.22</akka-streams-kafka.version>
<akka.version>2.5.31</akka.version>
<akka-streams-kafka.version>2.0.5</akka-streams-kafka.version>
<kafka.version>1.1.0</kafka.version>
<avro.version>1.8.2</avro.version>
<lift.version>3.4.1</lift.version>
<jetty.version>9.4.12.v20180830</jetty.version>
<log4j.version>2.15.0</log4j.version>
<log4j.version>2.17.1</log4j.version>
<obp-ri.version>2016.11-RC6-SNAPSHOT</obp-ri.version>
<!-- Common plugin settings -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

View File

@ -3,6 +3,11 @@
### Most recent changes at top of file
```
Date Commit Action
08/08/2022 1ff7bf0a removed props `meeting.tokbox_enabled`, `meeting.tokbox_api_key` and `meeting.tokbox_api_secret`.
removed three endpoints: getMeetings, getMeeting and createMeeting in V200.
05/08/2022 ba690c1f renamed props `transaction_request_challenge_ttl` to `transactionRequest.challenge.ttl.seconds`.
02/08/2022 7b06563f added new props `userAuthContextUpdateRequest.challenge.ttl.seconds`, default is 600 seconds.
01/08/2022 d94687d6 added new props `answer_transactionRequest_challenge_allowed_attempts`, default is 3 .
03/05/2022 5fe70270 added new props `transaction_request_challenge_ttl`, default is 600 seconds.
31/03/2022 a0262c3f added new value SIMPLE to props `transactionRequests_supported_types`
added new props `SIMPLE_OTP_INSTRUCTION_TRANSPORT`, default value is `DUMMY`