├── src ├── main │ ├── resources │ │ ├── .keep │ │ ├── cert │ │ │ ├── server.jks │ │ │ └── server.trust.jks │ │ ├── test.logback.xml │ │ ├── default.logback.xml │ │ ├── i18n │ │ │ ├── lift-core_en_GB.properties │ │ │ ├── lift-core_it_IT.properties │ │ │ ├── lift-core.properties │ │ │ └── lift-core_uk_UA.properties │ │ └── props │ │ │ └── sample.props.template │ ├── webapp │ │ ├── media │ │ │ ├── css │ │ │ │ ├── screen.css │ │ │ │ ├── reset.css │ │ │ │ ├── jquery.dropdown.min.css │ │ │ │ ├── highlight.js.min.css │ │ │ │ └── toastr.min.css │ │ │ ├── images │ │ │ │ ├── blank.gif │ │ │ │ ├── logo.png │ │ │ │ ├── nav.png │ │ │ │ ├── sort.png │ │ │ │ ├── add-off.png │ │ │ │ ├── add-on.png │ │ │ │ ├── cancel.png │ │ │ │ ├── comment.png │ │ │ │ ├── edit-on.png │ │ │ │ ├── favicon.ico │ │ │ │ ├── header.png │ │ │ │ ├── remove.png │ │ │ │ ├── submit.png │ │ │ │ ├── close-icon.png │ │ │ │ ├── edit-off.png │ │ │ │ ├── login-icon.png │ │ │ │ ├── moreInfo.png │ │ │ │ ├── nav-item.png │ │ │ │ ├── upload-off.png │ │ │ │ ├── upload-on.png │ │ │ │ ├── OBP_full_web.png │ │ │ │ ├── ajax-loader.gif │ │ │ │ ├── arrow-right.png │ │ │ │ ├── logo-footer.png │ │ │ │ ├── logo-header.png │ │ │ │ ├── logout-icon.png │ │ │ │ ├── nav-selected.png │ │ │ │ ├── select-arrow.png │ │ │ │ ├── OBP_logo_simple.png │ │ │ │ ├── feedback-button.png │ │ │ │ ├── money-in-icon.png │ │ │ │ ├── money-out-icon.png │ │ │ │ ├── polarize-logo.png │ │ │ │ ├── settings-icon.png │ │ │ │ ├── transaction-in.png │ │ │ │ ├── transaction-out.png │ │ │ │ ├── select-arrow-home.png │ │ │ │ ├── OpenBankProject_logo.jpg │ │ │ │ ├── home-table-exit-icon.png │ │ │ │ ├── home-table-enter-icon.png │ │ │ │ ├── home-table-paper-icon.png │ │ │ │ └── home-table-quote-icon.png │ │ │ └── js │ │ │ │ ├── website.js │ │ │ │ ├── notifications.js │ │ │ │ ├── scripts.js │ │ │ │ ├── vendor │ │ │ │ └── jquery.dropdown.min.js │ │ │ │ ├── toastr.min.js │ │ │ │ └── views.js │ │ ├── favicon.ico │ │ ├── font-awesome │ │ │ └── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ ├── templates-hidden │ │ │ ├── _tag.html │ │ │ ├── _comment.html │ │ │ ├── _transactionImage.html │ │ │ ├── _nav_account_settings.html │ │ │ ├── _dashboard_account.html │ │ │ └── default.html │ │ ├── WEB-INF │ │ │ └── web.xml │ │ ├── help.html │ │ ├── oauthcallback.html │ │ ├── correlated-user.html │ │ ├── debug-info.html │ │ ├── dd.html │ │ ├── about.html │ │ ├── 404.html │ │ ├── list-accounts.html │ │ ├── banks │ │ │ └── star │ │ │ │ └── accounts │ │ │ │ ├── star │ │ │ │ ├── settings.html │ │ │ │ ├── permissions │ │ │ │ │ └── create.html │ │ │ │ ├── management.html │ │ │ │ ├── permissions.html │ │ │ │ ├── create-income.html │ │ │ │ ├── create-expenditure.html │ │ │ │ ├── star.html │ │ │ │ ├── account-overview-dashboard.html │ │ │ │ ├── views │ │ │ │ │ └── list.html │ │ │ │ └── transactions │ │ │ │ │ └── star │ │ │ │ │ └── star.html │ │ │ │ └── create-bank-account.html │ │ ├── index.html │ │ └── my-accounts.html │ └── scala │ │ └── code │ │ ├── snippet │ │ ├── TimeHelpers.scala │ │ ├── AccountSettings.scala │ │ ├── CreateBankAccount.scala │ │ ├── CreateExpenditure.scala │ │ ├── CreateIncome.scala │ │ ├── Login.scala │ │ ├── CreatePermissionForm.scala │ │ ├── PermissionManagement.scala │ │ ├── CustomEditable.scala │ │ └── Dashboard.scala │ │ ├── Constant.scala │ │ ├── util │ │ ├── Helper.scala │ │ ├── ExceptionLogger.scala │ │ └── Util.scala │ │ ├── lib │ │ ├── ObpOAuthProvider.scala │ │ ├── SSLHelper.scala │ │ └── OAuthClient.scala │ │ └── widgets │ │ └── CustomTableSorter.scala └── test │ ├── resources │ └── .keep │ └── scala │ ├── LiftConsole.scala │ ├── RunWebApp.scala │ └── RunMtlsWebApp.scala ├── mvn_clean.sh ├── project ├── build.properties ├── plugins.sbt └── build.scala ├── mvn.sh ├── .gitignore ├── NOTICE ├── CONTRIBUTING.md └── README.md /src/main/resources/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/test/resources/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/webapp/media/css/screen.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mvn_clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mvn clean -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | #Project properties 2 | sbt.version=0.13.9 3 | -------------------------------------------------------------------------------- /mvn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export MAVEN_OPTS="-Xmx512m -Xms512m -XX:MaxPermSize=256m" 4 | 5 | mvn $* 6 | -------------------------------------------------------------------------------- /src/main/webapp/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/cert/server.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/resources/cert/server.jks -------------------------------------------------------------------------------- /src/main/webapp/media/images/blank.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/blank.gif -------------------------------------------------------------------------------- /src/main/webapp/media/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/logo.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/nav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/nav.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/sort.png -------------------------------------------------------------------------------- /src/main/resources/cert/server.trust.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/resources/cert/server.trust.jks -------------------------------------------------------------------------------- /src/main/webapp/media/images/add-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/add-off.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/add-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/add-on.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/cancel.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/comment.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/edit-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/edit-on.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/favicon.ico -------------------------------------------------------------------------------- /src/main/webapp/media/images/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/header.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/remove.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/submit.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/close-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/close-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/edit-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/edit-off.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/login-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/login-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/moreInfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/moreInfo.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/nav-item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/nav-item.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/upload-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/upload-off.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/upload-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/upload-on.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/OBP_full_web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/OBP_full_web.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/ajax-loader.gif -------------------------------------------------------------------------------- /src/main/webapp/media/images/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/arrow-right.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/logo-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/logo-footer.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/logo-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/logo-header.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/logout-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/logout-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/nav-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/nav-selected.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/select-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/select-arrow.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/OBP_logo_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/OBP_logo_simple.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/feedback-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/feedback-button.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/money-in-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/money-in-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/money-out-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/money-out-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/polarize-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/polarize-logo.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/settings-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/settings-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/transaction-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/transaction-in.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/transaction-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/transaction-out.png -------------------------------------------------------------------------------- /src/main/webapp/font-awesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/font-awesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/main/webapp/media/images/select-arrow-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/select-arrow-home.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/OpenBankProject_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/OpenBankProject_logo.jpg -------------------------------------------------------------------------------- /src/main/webapp/media/images/home-table-exit-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/home-table-exit-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/home-table-enter-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/home-table-enter-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/home-table-paper-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/home-table-paper-icon.png -------------------------------------------------------------------------------- /src/main/webapp/media/images/home-table-quote-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/media/images/home-table-quote-icon.png -------------------------------------------------------------------------------- /src/main/webapp/font-awesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/font-awesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/main/webapp/font-awesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/font-awesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/main/webapp/font-awesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/font-awesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/main/webapp/font-awesome/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenBankProject/Sofit/HEAD/src/main/webapp/font-awesome/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/main/webapp/templates-hidden/_tag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The tag goes here 4 | x 5 | 6 | -------------------------------------------------------------------------------- /src/main/webapp/media/js/website.js: -------------------------------------------------------------------------------- 1 | // $(function() { 2 | // $("body").polarize({ 3 | // "position": "right", 4 | // "images_dir": "/media/images/", 5 | // "default_topic_url": "https://polarize.it/polarize/socialfinanceapp_55868373368" 6 | // }); 7 | // }); -------------------------------------------------------------------------------- /src/main/resources/test.logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd HH:mm:ss} %t %c{0} [%p] %m%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/default.logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd HH:mm:ss} %t %c{0} [%p] %m%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/templates-hidden/_comment.html: -------------------------------------------------------------------------------- 1 |
  • 2 | #0 3 | The comment goes here 4 | Time ago goes here 5 | Commenter's email address goes here 6 |
  • 7 | -------------------------------------------------------------------------------- /src/main/webapp/templates-hidden/_transactionImage.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 |
    5 |
    A caption for the image
    6 | Bob
    sometime 7 |
    8 |
    9 | -------------------------------------------------------------------------------- /src/main/webapp/media/js/notifications.js: -------------------------------------------------------------------------------- 1 | var socialFinanceNotifications = { 2 | notify : function(msg) { 3 | toastr.info(msg); 4 | }, 5 | 6 | notifyError : function(msg) { 7 | toastr.error(msg); 8 | }, 9 | 10 | notifyReload : function(msg, delay) { 11 | toastr.info(msg); 12 | if (!delay) var delay = 1500; 13 | setTimeout(function() { 14 | window.location.reload(); 15 | }, delay); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.db 3 | .DS_Store 4 | *.scala.orig 5 | *.orig 6 | *.log 7 | .gitignore 8 | .idea 9 | .settings 10 | .classpath 11 | .project 12 | .cache 13 | src/main/resources/rebel.xml 14 | src/main/resources/props/* 15 | !src/main/resources/props/sample.props.template 16 | src/test/resources/props 17 | src/main/resources/git.properties 18 | 19 | src/main/webapp/WEB-INF/jetty.xml 20 | src/main/webapp/conf.html 21 | target/ 22 | *.iml 23 | -------------------------------------------------------------------------------- /src/main/scala/code/snippet/TimeHelpers.scala: -------------------------------------------------------------------------------- 1 | package code.snippet 2 | 3 | import java.text.SimpleDateFormat 4 | import java.util.Calendar 5 | 6 | import net.liftweb.util.Helpers._ 7 | 8 | /** 9 | * So we can put the current year in a template 10 | */ 11 | 12 | class TimeHelpers { 13 | 14 | val now = Calendar.getInstance().getTime() 15 | // create the date/time formatter 16 | val yearFormat = new SimpleDateFormat("yyyy") 17 | val nowYear = yearFormat.format(now) 18 | 19 | def currentYear = "#current_year" #> nowYear.toString 20 | } 21 | -------------------------------------------------------------------------------- /src/main/scala/code/Constant.scala: -------------------------------------------------------------------------------- 1 | package code 2 | 3 | import net.liftweb.util.Props 4 | 5 | object Constant { 6 | final val CUSTOM_OWNER_VIEW_ID = "owner" 7 | final val versionOfApi = Props.get("api_version").getOrElse("v4.0.0") 8 | final val versionOfApi121 = "v1.2.1" 9 | final val correlatedUserIdTargetCookieName = "CORRELATED_USER_ID_TARGET" 10 | final val correlatedUserIdBoundCookieName = "CORRELATED_USER_ID_BOUND" 11 | final val correlatedCustomerIdCreatedCookieName = "CORRELATED_CUSTOMER_ID_CREATED" 12 | final val linkBetweenCorrelatedUserAndCustomerCreatedCookieName = "LINK_BETWEEN_CORRELATED_USER_AND_CUSTOMER_CREATED" 13 | } 14 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | LiftFilter 10 | Lift Filter 11 | The Filter that intercepts lift calls 12 | net.liftweb.http.LiftFilter 13 | 14 | 15 | 16 | 17 | LiftFilter 18 | /* 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Open Bank Project - Sofi Web Application 2 | Copyright (C) 2011, 2012, TESOBE GmbH. 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | 17 | Email: contact@tesobe.com 18 | TESOBE GmbH. 19 | Osloer Str. 16/17 20 | Berlin 13359, Germany 21 | 22 | This product includes software developed at 23 | TESOBE (http://www.tesobe.com/) 24 | by 25 | Simon Redfern : simon AT tesobe DOT com 26 | Stefan Bethge : stefan AT tesobe DOT com 27 | Everett Sochowski : everett AT tesobe DOT com 28 | Ayoub Benali: ayoub AT tesobe DOT com 29 | -------------------------------------------------------------------------------- /src/test/scala/LiftConsole.scala: -------------------------------------------------------------------------------- 1 | /** 2 | Open Bank Project 3 | 4 | Copyright 2011,2012 TESOBE GmbH. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | import bootstrap.liftweb.Boot 19 | import scala.tools.nsc.MainGenericRunner 20 | import scala.sys._ 21 | 22 | object LiftConsole { 23 | def main(args : Array[String]) { 24 | // Instantiate your project's Boot file 25 | val b = new Boot() 26 | // Boot your project 27 | b.boot 28 | // Now run the MainGenericRunner to get your repl 29 | MainGenericRunner.main(args) 30 | // After the repl exits, then exit the scala script 31 | sys.exit(0) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/resources/i18n/lift-core_en_GB.properties: -------------------------------------------------------------------------------- 1 | login = Login 2 | logout = Logout 3 | views = Views 4 | private_accounts = Private accounts 5 | public_accounts = Public accounts 6 | my_accounts = My accounts 7 | account_name = Account Name 8 | you_are_logged_out = You are logged out. No authorised accounts available. 9 | enter_label = Enter a label... 10 | create_account_label = Create an account 11 | bank_name = Bank name 12 | account_label = Account name 13 | income_description = Description 14 | income_amount = Amount \u20ac 15 | payment_description = Description 16 | payment_amount = Amount \u20ac 17 | income = Income 18 | payment = Expenditure 19 | add_expenditure = Add expenditure 20 | button.save = Save 21 | api_documentation = API Documentation 22 | forgotten_password = Forgotten password? 23 | change_password = Change password 24 | new_label=Label 25 | expenditure.tags=Other,\ 26 | Telco&Internet,\ 27 | Family care,\ 28 | Insurance,\ 29 | Health,\ 30 | Restaurants,\ 31 | Spare time,\ 32 | Off line shopping,\ 33 | Transport,\ 34 | Rent and house,\ 35 | On-line shopping,\ 36 | Groceries 37 | income.tags=Salary,\ 38 | Transfer,\ 39 | Refund,\ 40 | Cash income,\ 41 | Pensions and yields,\ 42 | Extra and gifts -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 4 | ## Hello! 5 | 6 | Thank you for your interest in contributing to the Open Bank Project! 7 | 8 | ## Pull requests 9 | 10 | If submitting a pull request please read and sign our [CLA](http://github.com/OpenBankProject/OBP-API/blob/develop/Harmony_Individual_Contributor_Assignment_Agreement.txt) and send it to contact@tesobe.com - We'll send you back a code to include in the comment section of subsequent pull requests. 11 | 12 | Please reference Issue Numbers in your commits. 13 | 14 | ## Code comments 15 | 16 | Please comment your code ! :-) Imagine an engineer is trying to fix a production issue: she is working on a tiny screen, via a dodgy mobile Internet connection, in a sandstorm - Your code is fresh in your mind. Your comments could help her! 17 | 18 | ## Issues 19 | 20 | If would like to report an issue or suggest any kind of improvement please use Github Issues. 21 | 22 | ## Licenses 23 | 24 | Open Bank Project API, API Explorer and Sofi are dual licenced under the AGPL and commercial licenses. Open Bank Project SDKs are licenced under Apache 2 or MIT style licences. 25 | 26 | Please see the NOTICE for each project licence. 27 | 28 | ## Setup and Tests 29 | 30 | See the README for instructions on setup :-) 31 | 32 | Welcome! -------------------------------------------------------------------------------- /src/main/webapp/help.html: -------------------------------------------------------------------------------- 1 | 19 | 20 |
    21 | 30 |
    -------------------------------------------------------------------------------- /src/main/webapp/media/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } -------------------------------------------------------------------------------- /src/main/webapp/media/js/scripts.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | 4 | var project = {}; 5 | 6 | project.init = function() { 7 | project.counterpartiesFilter(); 8 | project.removeUserFromView(); 9 | project.managementTableSorter(); 10 | // project.transloadit(); 11 | project.fileUpload(); 12 | }; 13 | 14 | project.counterpartiesFilter = function() { 15 | $('.counterparties-table-head__cell').on('click', function() { 16 | $('.counterparties-table-head__cell').removeClass('counterparties-table-head__cell--active'); 17 | $(this).addClass('counterparties-table-head__cell--active'); 18 | }); 19 | }; 20 | 21 | project.removeUserFromView = function() { 22 | $('.users-table-body__cell .remove').click(function () { 23 | $(this).closest('.row').css('background-color', '#CC0000').fadeOut(1000, function() {$(this).remove();}); 24 | }); 25 | }; 26 | 27 | project.managementTableSorter = function() { 28 | $("#management .tablesorter").tablesorter(); 29 | } 30 | 31 | project.transloadit = function() { 32 | $('#imageUploader').transloadit({ 33 | wait: true 34 | }); 35 | } 36 | 37 | project.fileUpload = function() { 38 | $(".file-upload").change(function() { 39 | $(this).siblings('.file-upload-filename').html(this.value); 40 | }); 41 | } 42 | 43 | $(document).ready(project.init); 44 | 45 | })(jQuery); 46 | 47 | -------------------------------------------------------------------------------- /src/main/webapp/oauthcallback.html: -------------------------------------------------------------------------------- 1 | 32 |
    33 | 34 | Sorry! There was an error logging in. 35 | 36 |
    37 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | resolvers += Classpaths.typesafeResolver 2 | 3 | // addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse" % "1.5.0") 4 | 5 | // resolvers += "sbt-deploy-repo" at "http://reaktor.github.com/sbt-deploy/maven" 6 | // addSbtPlugin("fi.reaktor" %% "sbt-deploy" % "0.3.1-SNAPSHOT") 7 | 8 | 9 | //xsbt-web-plugin 10 | addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "2.1.0") 11 | 12 | //resolvers += "Web plugin repo" at "http://siasia.github.com/maven2" 13 | //libraryDependencies <+= sbtVersion(v => v match { 14 | //case "0.11.0" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.0-0.2.8" 15 | //case "0.11.1" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.1-0.2.10" 16 | //case "0.11.2" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.2-0.2.11" 17 | //case "0.11.3" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.3-0.2.11.1" 18 | //}) 19 | 20 | //sbteclipse 21 | resolvers += { 22 | val typesafeRepoUrl = new java.net.URL("http://repo.typesafe.com/typesafe/releases") 23 | val pattern = Patterns(false, "[organisation]/[module]/[sbtversion]/[revision]/[type]s/[module](-[classifier])-[revision].[ext]") 24 | Resolver.url("Typesafe Repository", typesafeRepoUrl)(pattern) 25 | } 26 | 27 | addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0") 28 | addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2") 29 | 30 | //sbt-idea 31 | resolvers += "sbt-idea-repo" at "http://mpeltonen.github.com/maven/" 32 | 33 | addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0") 34 | -------------------------------------------------------------------------------- /src/main/webapp/correlated-user.html: -------------------------------------------------------------------------------- 1 | 19 | 20 |
    21 | 35 |
    -------------------------------------------------------------------------------- /src/main/webapp/media/css/jquery.dropdown.min.css: -------------------------------------------------------------------------------- 1 | .jq-dropdown{position:absolute;z-index:1039;display:none}.jq-dropdown .jq-dropdown-menu,.jq-dropdown .jq-dropdown-panel{min-width:160px;max-width:360px;list-style:none;background:#fff;border:solid 1px #ddd;border-radius:4px;box-shadow:0 5px 10px rgba(0,0,0,0.2);overflow:visible;padding:4px 0;margin:0}.jq-dropdown .jq-dropdown-panel{padding:10px}.jq-dropdown.jq-dropdown-tip{margin-top:8px}.jq-dropdown.jq-dropdown-tip:before{position:absolute;top:-6px;left:9px;content:"";border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ddd;display:inline-block}.jq-dropdown.jq-dropdown-tip:after{position:absolute;top:-5px;left:10px;content:"";border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;display:inline-block}.jq-dropdown.jq-dropdown-tip.jq-dropdown-anchor-right:before{left:auto;right:9px}.jq-dropdown.jq-dropdown-tip.jq-dropdown-anchor-right:after{left:auto;right:10px}.jq-dropdown.jq-dropdown-scroll .jq-dropdown-menu,.jq-dropdown.jq-dropdown-scroll .jq-dropdown-panel{max-height:180px;overflow:auto}.jq-dropdown .jq-dropdown-menu li{list-style:none;padding:0 0;margin:0;line-height:18px}.jq-dropdown .jq-dropdown-menu li>a,.jq-dropdown .jq-dropdown-menu label{display:block;color:inherit;text-decoration:none;line-height:18px;padding:3px 15px;margin:0;white-space:nowrap}.jq-dropdown .jq-dropdown-menu li>a:hover,.jq-dropdown .jq-dropdown-menu label:hover{background-color:#f2f2f2;color:inherit;cursor:pointer}.jq-dropdown .jq-dropdown-menu .jq-dropdown-divider{font-size:1px;border-top:solid 1px #e5e5e5;padding:0;margin:5px 0} 2 | -------------------------------------------------------------------------------- /src/main/scala/code/util/Helper.scala: -------------------------------------------------------------------------------- 1 | package code.util 2 | 3 | import code.Constant._ 4 | import code.lib.ObpAPI.getAccount 5 | import code.lib.ObpJson.AccountJson 6 | import net.liftweb.common._ 7 | import net.liftweb.util.Props 8 | 9 | 10 | object Helper { 11 | 12 | 13 | 14 | // From bankId / accountId 15 | def getAccountTitle (bankId: String, accountId: String) : String = { 16 | val accountJsonBox = getAccount(bankId, accountId, CUSTOM_OWNER_VIEW_ID) 17 | 18 | val accountTitle = accountJsonBox match { 19 | case Full(accountJson) => getAccountTitle(accountJson) 20 | case _ => "Unknown Account" 21 | } 22 | accountTitle 23 | } 24 | 25 | 26 | /* 27 | Returns a string which can be used for the title of the account 28 | Uses the Label else Id if possible 29 | */ 30 | def getAccountTitle(accountJson: AccountJson ) : String = { 31 | accountJson.label.getOrElse(accountJson.id.getOrElse("---")) 32 | } 33 | 34 | 35 | def hasManagementAccess (accountJson: AccountJson ) : Boolean = { 36 | val availableViews = accountJson.views_available.toList.flatten 37 | availableViews.exists(view => view.id == Some(CUSTOM_OWNER_VIEW_ID)) 38 | } 39 | 40 | 41 | def getHostname(): String = { 42 | Props.get("base_url", "") match { 43 | case s: String if s.nonEmpty => s.split(":").lift(1) match { 44 | case Some(s) => s.replaceAll("\\/", "").replaceAll("\\.", "-") 45 | case None => "unknown" 46 | } 47 | case _ => "unknown" 48 | } 49 | } 50 | 51 | trait MdcLoggable extends Loggable { 52 | MDC.put("host" -> getHostname) 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/webapp/debug-info.html: -------------------------------------------------------------------------------- 1 | 19 | 20 |
    21 | 22 | 35 | 36 | 37 | 38 | 39 |
    -------------------------------------------------------------------------------- /src/main/webapp/dd.html: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 | 30 |
    31 | 32 | 33 | 34 | 35 |
    36 |

    YOUR ACCOUNTS DD

    37 | 42 |
    43 | 44 | 45 | 46 | 47 |
    48 |

    Centre for Transparency & Civic Engagement (PARTICIP) AND Fairnopoly

    49 |
    50 | 51 | 52 | 53 | 54 |
    55 | 56 | -------------------------------------------------------------------------------- /src/main/webapp/about.html: -------------------------------------------------------------------------------- 1 | 19 | 20 |
    21 | 22 | 41 | 42 | 43 | 44 | 45 |
    46 | -------------------------------------------------------------------------------- /src/main/webapp/404.html: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |
    30 | 31 | 50 | 51 |
    52 | -------------------------------------------------------------------------------- /src/main/scala/code/snippet/AccountSettings.scala: -------------------------------------------------------------------------------- 1 | package code.snippet 2 | 3 | import code.Constant._ 4 | import code.lib.ObpAPI.{getAccount, updateAccountLabel} 5 | import code.util.Helper.{MdcLoggable, getAccountTitle} 6 | import net.liftweb.http.SHtml 7 | import net.liftweb.http.js.JE.Call 8 | import net.liftweb.http.js.JsCmd 9 | import net.liftweb.http.js.JsCmds.SetHtml 10 | import net.liftweb.util.Helpers._ 11 | 12 | import scala.xml.{NodeSeq, Text} 13 | 14 | 15 | /* 16 | For maintaining permissions on the views (entitlements on the account) 17 | */ 18 | class AccountSettings(params: List[String]) extends MdcLoggable { 19 | val bankId = params(0) 20 | val accountId = params(1) 21 | val accountJson = getAccount(bankId, accountId, CUSTOM_OWNER_VIEW_ID).openOrThrowException("Could not open accountJson") 22 | def accountTitle = ".account-title *" #> getAccountTitle(accountJson) 23 | 24 | //set up ajax handlers to edit account label 25 | def editLabel(xhtml: NodeSeq): NodeSeq = { 26 | var newLabel = "" 27 | 28 | def process(): JsCmd = { 29 | logger.debug(s"AccountSettings.editLabel.process: edit label $newLabel") 30 | val result = updateAccountLabel(bankId, accountId, newLabel) 31 | if (result.isDefined) { 32 | val msg = "Label " + newLabel + " has been set" 33 | SetHtml("account-title", Text(newLabel)) & 34 | Call("socialFinanceNotifications.notify", msg).cmd 35 | } else { 36 | val msg = "Sorry, Label" + newLabel + " could not be set ("+ result +")" 37 | Call("socialFinanceNotifications.notifyError", msg).cmd 38 | } 39 | } 40 | 41 | ( 42 | // Bind newViewName field to variable (e.g. http://chimera.labs.oreilly.com/books/1234000000030/ch03.html) 43 | "@new_label" #> SHtml.text(accountJson.label.getOrElse(""), s => newLabel = s) & 44 | // Replace the type=submit with Javascript that makes the ajax call. 45 | "type=submit" #> SHtml.ajaxSubmit("Save account label", process) 46 | ).apply(xhtml) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/scala/code/lib/ObpOAuthProvider.scala: -------------------------------------------------------------------------------- 1 | package code.lib 2 | 3 | import java.io.IOException 4 | import java.net.{HttpURLConnection, MalformedURLException} 5 | 6 | import oauth.signpost.AbstractOAuthProvider 7 | import oauth.signpost.basic.{HttpURLConnectionRequestAdapter, HttpURLConnectionResponseAdapter} 8 | import oauth.signpost.http.{HttpRequest, HttpResponse} 9 | 10 | 11 | /** 12 | * Library https://github.com/mttkay/signpost we use for OAuth1 does not implement MTLS connection. 13 | * In order to support it ObpOAuthProvider inherit AbstractOAuthProvider and override function createRequest 14 | * in a way that {@link HttpURLConnection} is used in case the props ssl_client_auth=false 15 | * or {@link HttpsURLConnection} in case the props ssl_client_auth=true 16 | * to receive tokens from a service provider. 17 | */ 18 | @SerialVersionUID(1L) 19 | class ObpOAuthProvider(val requestTokenEndpointUrl: String, val accessTokenEndpointUrl: String, val authorizationWebsiteUrl: String) extends AbstractOAuthProvider(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl) { 20 | @throws[MalformedURLException] 21 | @throws[IOException] 22 | override protected def createRequest(endpointUrl: String): HttpRequest = { 23 | val connection = SSLHelper.getConnection(endpointUrl) 24 | connection.setRequestMethod("POST") 25 | connection.setAllowUserInteraction(false) 26 | connection.setRequestProperty("Content-Length", "0") 27 | new HttpURLConnectionRequestAdapter(connection) 28 | } 29 | 30 | @throws[IOException] 31 | override protected def sendRequest(request: HttpRequest): HttpResponse = { 32 | val connection = request.unwrap.asInstanceOf[HttpURLConnection] 33 | connection.connect() 34 | new HttpURLConnectionResponseAdapter(connection) 35 | } 36 | 37 | override protected def closeConnection(request: HttpRequest, response: HttpResponse): Unit = { 38 | val connection = request.unwrap.asInstanceOf[HttpURLConnection] 39 | if (connection != null) connection.disconnect() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/webapp/list-accounts.html: -------------------------------------------------------------------------------- 1 | 31 |
    32 | 33 | 34 | 35 | 54 |
    55 | -------------------------------------------------------------------------------- /src/main/webapp/templates-hidden/_nav_account_settings.html: -------------------------------------------------------------------------------- 1 | 40 | -------------------------------------------------------------------------------- /src/main/scala/code/util/ExceptionLogger.scala: -------------------------------------------------------------------------------- 1 | package code.util 2 | 3 | import net.liftweb.common.{Failure, Full, Box} 4 | import code.util.Helper.MdcLoggable 5 | import net.liftweb.util.{Mailer, Props} 6 | 7 | object MyExceptionLogger extends MdcLoggable{ 8 | import net.liftweb.http.Req 9 | 10 | def unapply(in: (Props.RunModes.Value, Req, Throwable)): Option[(Props.RunModes.Value, Req, Throwable)] = { 11 | import net.liftweb.util.Helpers.now 12 | import Mailer.{From, To, Subject, PlainMailBodyType} 13 | 14 | val outputStream = new java.io.ByteArrayOutputStream 15 | val printStream = new java.io.PrintStream(outputStream) 16 | in._3.printStackTrace(printStream) 17 | val currentTime = now.toString 18 | val stackTrace = new String(outputStream.toByteArray) 19 | val error = currentTime + ": " + stackTrace 20 | val host = Props.get("base_url", "unknown host") 21 | 22 | val mailSent = for { 23 | from <- Props.get("mail.exception.sender.address") ?~ "Could not send mail: Missing props param for 'from'" 24 | // no spaces, comma separated e.g. mail.api.consumer.registered.notification.addresses=notify@example.com,notify2@example.com,notify3@example.com 25 | toAddressesString <- Props.get("mail.exception.registered.notification.addresses") ?~ "Could not send mail: Missing props param for 'to'" 26 | } yield { 27 | 28 | //technically doesn't work for all valid email addresses so this will mess up if someone tries to send emails to "foo,bar"@example.com 29 | val to = toAddressesString.split(",").toList 30 | val toParams = to.map(To(_)) 31 | val params = PlainMailBodyType(error) :: toParams 32 | 33 | //this is an async call 34 | Mailer.sendMail( 35 | From(from), 36 | Subject("you got an exception on "+host), 37 | params :_* 38 | ) 39 | } 40 | 41 | //if Mailer.sendMail wasn't called (note: this actually isn't checking if the mail failed to send as that is being done asynchronously) 42 | if(mailSent.isEmpty) 43 | logger.warn("Exception notification failed: " +mailSent) 44 | 45 | None 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/scala/RunWebApp.scala: -------------------------------------------------------------------------------- 1 | /** 2 | Open Bank Project - Sofi Web Application 3 | Copyright (C) 2011 - 2021, TESOBE GmbH. 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | 18 | Email: contact@tesobe.com 19 | TESOBE GmbH. 20 | Osloer Str. 16/17 21 | Berlin 13359, Germany 22 | 23 | This product includes software developed at 24 | TESOBE (http://www.tesobe.com/) 25 | by 26 | Simon Redfern : simon AT tesobe DOT com 27 | Stefan Bethge : stefan AT tesobe DOT com 28 | Everett Sochowski : everett AT tesobe DOT com 29 | Ayoub Benali: ayoub AT tesobe DOT com 30 | */ 31 | 32 | import net.liftweb.util.Props 33 | import org.mortbay.jetty.Server 34 | import org.mortbay.jetty.webapp.WebAppContext 35 | import org.mortbay.jetty.nio._ 36 | 37 | object RunWebApp extends App { 38 | val server = new Server 39 | val scc = new SelectChannelConnector 40 | scc.setPort(Props.getInt("dev.port", 8080)) 41 | server.setConnectors(Array(scc)) 42 | 43 | val context = new WebAppContext() 44 | context.setServer(server) 45 | context.setContextPath("/") 46 | context.setWar("src/main/webapp") 47 | 48 | server.addHandler(context) 49 | 50 | try { 51 | println(">>> STARTING EMBEDDED JETTY SERVER, PRESS ANY KEY TO STOP") 52 | server.start() 53 | while (System.in.available() == 0) { 54 | Thread.sleep(5000) 55 | } 56 | server.stop() 57 | server.join() 58 | } catch { 59 | case exc : Exception => { 60 | exc.printStackTrace() 61 | sys.exit(100) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/webapp/media/js/vendor/jquery.dropdown.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Dropdown: A simple dropdown plugin 3 | * 4 | * Contribute: https://github.com/claviska/jquery-dropdown 5 | * 6 | * @license: MIT license: http://opensource.org/licenses/MIT 7 | * 8 | */ 9 | jQuery&&function($){function t(t,e){var n=t?$(this):e,d=$(n.attr("data-jq-dropdown")),a=n.hasClass("jq-dropdown-open");if(t){if($(t.target).hasClass("jq-dropdown-ignore"))return;t.preventDefault(),t.stopPropagation()}else if(n!==e.target&&$(e.target).hasClass("jq-dropdown-ignore"))return;o(),a||n.hasClass("jq-dropdown-disabled")||(n.addClass("jq-dropdown-open"),d.data("jq-dropdown-trigger",n).show(),r(),d.trigger("show",{jqDropdown:d,trigger:n}))}function o(t){var o=t?$(t.target).parents().addBack():null;if(o&&o.is(".jq-dropdown")){if(!o.is(".jq-dropdown-menu"))return;if(!o.is("A"))return}$(document).find(".jq-dropdown:visible").each(function(){var t=$(this);t.hide().removeData("jq-dropdown-trigger").trigger("hide",{jqDropdown:t})}),$(document).find(".jq-dropdown-open").removeClass("jq-dropdown-open")}function r(){var t=$(".jq-dropdown:visible").eq(0),o=t.data("jq-dropdown-trigger"),r=o?parseInt(o.attr("data-horizontal-offset")||0,10):null,e=o?parseInt(o.attr("data-vertical-offset")||0,10):null;0!==t.length&&o&&t.css(t.hasClass("jq-dropdown-relative")?{left:t.hasClass("jq-dropdown-anchor-right")?o.position().left-(t.outerWidth(!0)-o.outerWidth(!0))-parseInt(o.css("margin-right"),10)+r:o.position().left+parseInt(o.css("margin-left"),10)+r,top:o.position().top+o.outerHeight(!0)-parseInt(o.css("margin-top"),10)+e}:{left:t.hasClass("jq-dropdown-anchor-right")?o.offset().left-(t.outerWidth()-o.outerWidth())+r:o.offset().left+r,top:o.offset().top+o.outerHeight()+e})}$.extend($.fn,{jqDropdown:function(r,e){switch(r){case"show":return t(null,$(this)),$(this);case"hide":return o(),$(this);case"attach":return $(this).attr("data-jq-dropdown",e);case"detach":return o(),$(this).removeAttr("data-jq-dropdown");case"disable":return $(this).addClass("jq-dropdown-disabled");case"enable":return o(),$(this).removeClass("jq-dropdown-disabled")}}}),$(document).on("click.jq-dropdown","[data-jq-dropdown]",t),$(document).on("click.jq-dropdown",o),$(window).on("resize",r)}(jQuery); -------------------------------------------------------------------------------- /src/main/webapp/templates-hidden/_dashboard_account.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43 | -------------------------------------------------------------------------------- /src/main/resources/i18n/lift-core_it_IT.properties: -------------------------------------------------------------------------------- 1 | login = Accedi 2 | logout = Esci 3 | views = Visualizzazioni 4 | private_accounts = Conti privati 5 | public_accounts = Conti pubblici 6 | my_accounts = I miei registri 7 | account_name = Nome utente 8 | you_are_logged_out = Sei disconnesso. Nessun account autorizzato disponibile. 9 | enter_label = Crea un tag 10 | create_account_label = Crea un conto in banca 11 | bank_name = nome della banca 12 | account_label = Etichetta dell'account 13 | income_description = Descrizione del reddito 14 | income_amount = Importo del reddito 15 | payment_description = Descrizione 16 | payment_amount = Importo del pagamento 17 | payment_category = Categoria 18 | income = Reddito 19 | payment = Pagamento 20 | expenditure = Spesa 21 | add_expenditure = Aggiungi una spesa 22 | add_income = Aggiungi un'entrata 23 | button.save = Salva 24 | button_cancel = Annulla 25 | button_show = Vedi 26 | api_documentation = Documentazione API 27 | forgotten_password = Hai dimenticato la password? 28 | change_password = Cambia la password 29 | expenditure.tags=Spesa alimentari,\ 30 | Telefono e Internet,\ 31 | Spese familiari,\ 32 | Assicurazioni,\ 33 | Spese mediche,\ 34 | Ristorante,\ 35 | Tempo libero,\ 36 | Acquisiti in negozio,\ 37 | Trasporti,\ 38 | Casa,\ 39 | Acquisti on line,\ 40 | Extra e imprevisti 41 | income.tags=Stipendio,\ 42 | Bonifico,\ 43 | Rimborso spese,\ 44 | Entrate in contanti,\ 45 | Rendita e pensione,\ 46 | Extra e regali 47 | months_ago = Periodo 48 | about = Chi siamo 49 | help_info = Se desiderate accedere o modificare i vostri dati personali o richiedere la cancellazione, l'esportazione o il trasferimento delle informazioni che vi riguardano, potete inviarci un'e-mail con la vostra richiesta a gdpr@microfinanza.it 50 | balance = Bilancio 51 | balance_colon = Bilancio: 52 | add_tag = aggiungi un tag 53 | add_image = aggiungi un'immagine 54 | add_comment = aggiungi un commento 55 | images = Immagini 56 | add_a_new_image = aggiungi una nuova immagine 57 | tags = Tag 58 | comments = Commenti 59 | add_a_comment = Aggiungi un commento qui 60 | months_ago_list = 1::mese,2::mesi,3::mesi,4::mesi,5::mesi,6::mesi,7::mesi,8::mesi,9::mesi,10::mesi,11::mesi,12::mesi 61 | profile_completeness = Completezza del profilo 62 | credit_score = Punteggio di credito -------------------------------------------------------------------------------- /src/main/webapp/media/css/highlight.js.min.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:0.5em;background:#f0f0f0;-webkit-text-size-adjust:none}.hljs,.hljs-subst,.hljs-tag .hljs-title,.nginx .hljs-title{color:black}.hljs-string,.hljs-title,.hljs-constant,.hljs-parent,.hljs-tag .hljs-value,.hljs-rule .hljs-value,.hljs-preprocessor,.hljs-pragma,.hljs-name,.haml .hljs-symbol,.ruby .hljs-symbol,.ruby .hljs-symbol .hljs-string,.hljs-template_tag,.django .hljs-variable,.smalltalk .hljs-class,.hljs-addition,.hljs-flow,.hljs-stream,.bash .hljs-variable,.pf .hljs-variable,.apache .hljs-tag,.apache .hljs-cbracket,.tex .hljs-command,.tex .hljs-special,.erlang_repl .hljs-function_or_atom,.asciidoc .hljs-header,.markdown .hljs-header,.coffeescript .hljs-attribute,.tp .hljs-variable{color:#800}.smartquote,.hljs-comment,.hljs-annotation,.diff .hljs-header,.hljs-chunk,.asciidoc .hljs-blockquote,.markdown .hljs-blockquote{color:#888}.hljs-number,.hljs-date,.hljs-regexp,.hljs-literal,.hljs-hexcolor,.smalltalk .hljs-symbol,.smalltalk .hljs-char,.go .hljs-constant,.hljs-change,.lasso .hljs-variable,.makefile .hljs-variable,.asciidoc .hljs-bullet,.markdown .hljs-bullet,.asciidoc .hljs-link_url,.markdown .hljs-link_url{color:#080}.hljs-label,.ruby .hljs-string,.hljs-decorator,.hljs-filter .hljs-argument,.hljs-localvars,.hljs-array,.hljs-attr_selector,.hljs-important,.hljs-pseudo,.hljs-pi,.haml .hljs-bullet,.hljs-doctype,.hljs-deletion,.hljs-envvar,.hljs-shebang,.apache .hljs-sqbracket,.nginx .hljs-built_in,.tex .hljs-formula,.erlang_repl .hljs-reserved,.hljs-prompt,.asciidoc .hljs-link_label,.markdown .hljs-link_label,.vhdl .hljs-attribute,.clojure .hljs-attribute,.asciidoc .hljs-attribute,.lasso .hljs-attribute,.coffeescript .hljs-property,.hljs-phony{color:#88f}.hljs-keyword,.hljs-id,.hljs-title,.hljs-built_in,.css .hljs-tag,.hljs-doctag,.smalltalk .hljs-class,.hljs-winutils,.bash .hljs-variable,.pf .hljs-variable,.apache .hljs-tag,.hljs-type,.hljs-typename,.tex .hljs-command,.asciidoc .hljs-strong,.markdown .hljs-strong,.hljs-request,.hljs-status,.tp .hljs-data,.tp .hljs-io{font-weight:bold}.asciidoc .hljs-emphasis,.markdown .hljs-emphasis,.tp .hljs-units{font-style:italic}.nginx .hljs-built_in{font-weight:normal}.coffeescript .javascript,.javascript .xml,.lasso .markup,.tex .hljs-formula,.xml .javascript,.xml .vbscript,.xml .css,.xml .hljs-cdata{opacity:0.5} -------------------------------------------------------------------------------- /src/main/scala/code/snippet/CreateBankAccount.scala: -------------------------------------------------------------------------------- 1 | package code.snippet 2 | 3 | import code.lib.ObpAPI 4 | import code.lib.ObpAPI.createAccount 5 | import code.lib.ObpJson.BankJson400 6 | import code.util.Helper.MdcLoggable 7 | import net.liftweb.common.Box 8 | import net.liftweb.http.js.JE.Call 9 | import net.liftweb.http.js.JsCmd 10 | import net.liftweb.http.js.JsCmds.SetHtml 11 | import net.liftweb.http.{RequestVar, SHtml} 12 | import net.liftweb.util.Helpers._ 13 | 14 | import scala.collection.immutable.List 15 | import scala.xml.{NodeSeq, Text} 16 | 17 | 18 | class CreateBankAccount(params: List[BankJson400]) extends MdcLoggable { 19 | 20 | private object bankVar extends RequestVar("") 21 | private object userIdVar extends RequestVar("") 22 | 23 | 24 | def editLabel(xhtml: NodeSeq): NodeSeq = { 25 | var newLabel = "" 26 | val bankId = "user." + ObpAPI.currentUser.map(_.user_id).getOrElse(System.currentTimeMillis()) 27 | val listOfBanks = params 28 | .filter(_.id == bankId) 29 | .map(b => (b.id, b.full_name)) 30 | 31 | def process(): JsCmd = { 32 | ObpAPI.currentUser.map { 33 | u => userIdVar.set(u.user_id) 34 | } 35 | logger.debug(s"CreateBankAccount.editLabel.process: edit label $newLabel") 36 | if(listOfBanks.size == 1) { 37 | val result = createAccount(bankVar.is, newLabel, userIdVar.is) 38 | if (result.isDefined) { 39 | val msg = "Saved" 40 | SetHtml("account-title", Text(newLabel)) & 41 | Call("socialFinanceNotifications.notify", msg).cmd 42 | } else { 43 | val msg = "Sorry, the new account with the label" + newLabel + " could not be set ("+ result +")" 44 | Call("socialFinanceNotifications.notifyError", msg).cmd 45 | } 46 | } else { 47 | val msg = "Sorry, the new account with the label " + newLabel + " could not be set due to unresolved bank id value" 48 | Call("socialFinanceNotifications.notifyError", msg).cmd 49 | } 50 | } 51 | 52 | ( 53 | "@new_label" #> SHtml.text("", s => newLabel = s) & 54 | "#bank-id" #> SHtml.select(listOfBanks, Box!! bankVar.is, bankVar(_)) & 55 | // Replace the type=submit with Javascript that makes the ajax call. 56 | "type=submit" #> SHtml.ajaxSubmit("Create", process) 57 | ).apply(xhtml) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/scala/code/snippet/CreateExpenditure.scala: -------------------------------------------------------------------------------- 1 | package code.snippet 2 | 3 | import code.Constant._ 4 | import code.lib.ObpAPI 5 | import code.lib.ObpAPI.{createOutcome, getAccount} 6 | import code.util.Helper.{MdcLoggable, getAccountTitle} 7 | import net.liftweb.common.Box 8 | import net.liftweb.http.js.JE.Call 9 | import net.liftweb.http.js.JsCmd 10 | import net.liftweb.http.{RequestVar, S, SHtml} 11 | import net.liftweb.util.Helpers._ 12 | 13 | import scala.xml.NodeSeq 14 | 15 | 16 | class CreateExpenditure(params: List[String]) extends MdcLoggable { 17 | private object tagVar extends RequestVar("") 18 | val bankId = params(0) 19 | val accountId = params(1) 20 | val accountJson = getAccount(bankId, accountId, CUSTOM_OWNER_VIEW_ID).openOrThrowException("Could not open accountJson") 21 | def accountTitle = ".account-title *" #> getAccountTitle(accountJson) 22 | 23 | 24 | def addPayment(xhtml: NodeSeq): NodeSeq = { 25 | var outcomeDescription = "" 26 | var outcomeAmount = 0D 27 | val listOfTags: Seq[(String, String)] = S.?("expenditure.tags"). 28 | split(",").toList.map(_.trim).map(i => i.replaceAll("_", "/")).map(i => (i,i)) 29 | 30 | def process(): JsCmd = { 31 | logger.debug(s"CreateOutcome.addOutcome.process: edit label $outcomeDescription") 32 | val result = createOutcome(bankId, accountId, outcomeDescription, outcomeAmount.toString, "EUR") 33 | if (result.isDefined) { 34 | val transactionId = result.map(_.transaction_id).getOrElse("") 35 | val addTags = ObpAPI.addTags(bankId, accountId, "owner", transactionId, List(tagVar.is)) 36 | logger.debug(s"CreateOutcome.addOutcome.process.addTags $addTags") 37 | val msg = "Saved" 38 | Call("socialFinanceNotifications.notify", msg).cmd 39 | S.redirectTo(s"/banks/$bankId/accounts/$accountId/owner") 40 | } else { 41 | val msg = s"Sorry, Expenditure $outcomeDescription could not be added ($result)" 42 | Call("socialFinanceNotifications.notifyError", msg).cmd 43 | } 44 | } 45 | 46 | ( 47 | "@payment_description" #> SHtml.text("", s => outcomeDescription = s) & 48 | "#payment_category" #> SHtml.select(listOfTags, Box!! tagVar.is, tagVar(_)) & 49 | "@payment_amount" #> SHtml.number(0D, (s:Double) => outcomeAmount = s, 0D, 1000000000D, 0.01D) & 50 | // Replace the type=submit with Javascript that makes the ajax call. 51 | "type=submit" #> SHtml.ajaxSubmit(S.?("button.save"), process) 52 | ).apply(xhtml) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/resources/i18n/lift-core.properties: -------------------------------------------------------------------------------- 1 | login = Login 2 | logout = Logout 3 | views = Views 4 | private_accounts = Private accounts 5 | public_accounts = Public accounts 6 | my_accounts = My accounts 7 | account_name = Account Name 8 | you_are_logged_out = You are logged out. No authorised accounts available. 9 | enter_label = Enter a label... 10 | create_account_label = Create new account 11 | bank_name = Bank name 12 | #account_label = Account label 13 | account_label = Account name 14 | income_description = Description 15 | income_amount = Amount \u20ac 16 | payment_description = Description 17 | payment_amount = Amount \u20ac 18 | payment_category = Category 19 | income = Income 20 | payment = Expenditure 21 | expenditure = Expenditure 22 | add_expenditure = Add expenditure 23 | add_income = Add income 24 | button.save = Save 25 | button_cancel = Cancel 26 | button_show = Show 27 | api_documentation = API Documentation 28 | forgotten_password = Forgotten password? 29 | change_password = Change password 30 | new_label=Label 31 | expenditure.tags=Other,\ 32 | Telco&Internet,\ 33 | Family care,\ 34 | Insurance,\ 35 | Health,\ 36 | Restaurants,\ 37 | Spare time,\ 38 | Off line shopping,\ 39 | Transport,\ 40 | Rent and house,\ 41 | On-line shopping,\ 42 | Groceries 43 | income.tags=Salary,\ 44 | Transfer,\ 45 | Refund,\ 46 | Cash income,\ 47 | Pensions and yields,\ 48 | Extra and gifts 49 | months_ago = Period 50 | about = About 51 | about_info = Welcome to the IncludiMI App. IncludiMI is an innovative project which aims to provide financial identity to the underbanked. IncludiMI is led by Experian, Associazione Microfinanza e Sviluppo ONLUS, Associazione MicroLab and TESOBE. 52 | help_info = If you wish to access or amend any Personal Data we hold about you, or to request that we delete, export or transfer any information about you, you may email us with your request at dpoitaly@experian.com 53 | help = Help 54 | balance = Balance 55 | balance_colon = Balance: 56 | add_tag = ADD TAG 57 | add_image = ADD IMAGE 58 | add_comment = ADD COMMENT 59 | images = Images 60 | add_a_new_image = Add a new iage 61 | tags = Tags 62 | comments = Comments 63 | add_a_comment = Add a comment here 64 | months_ago_list = 1::month,2::months,3::months,4::months,5::months,6::months,7::months,8::months,9::months,10::months,11::months,12::months 65 | profile_completeness = Profile completeness 66 | credit_score = Credit score 67 | source_code_text = The source code for this application is available here: 68 | debug_info_text = Data we store related to your account includes the following: 69 | -------------------------------------------------------------------------------- /src/main/webapp/banks/star/accounts/star/settings.html: -------------------------------------------------------------------------------- 1 | 29 | 30 | 34 | 35 |
    36 | 37 | 38 | 62 | 63 |
    64 | -------------------------------------------------------------------------------- /src/main/webapp/banks/star/accounts/create-bank-account.html: -------------------------------------------------------------------------------- 1 | 26 | 27 | 31 | 32 |
    33 | 34 | 35 | 69 | 70 |
    71 | -------------------------------------------------------------------------------- /src/main/scala/code/lib/SSLHelper.scala: -------------------------------------------------------------------------------- 1 | package code.lib 2 | 3 | import java.io.FileInputStream 4 | import java.net.{HttpURLConnection, URL} 5 | import java.security.{KeyStore, SecureRandom} 6 | 7 | import javax.net.ssl.{TrustManagerFactory, _} 8 | import net.liftweb.util.Props 9 | 10 | object SSLHelper { 11 | 12 | 13 | private lazy val sSLSocketFactory = { 14 | val keystoreFile: String = Props.get("ssl_keystore_location").openOrThrowException("props value of ssl_keystore_location is missing") 15 | val keystorePassword = Props.get("ssl_keystore_password", "") 16 | val truststoreFile = Props.get("ssl_truststore_location","") 17 | val truststorePassword = Props.get("ssl_truststore_password", "") 18 | val keyPassword = Props.get("ssl_key_password", "") 19 | 20 | 21 | 22 | val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) 23 | val keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm) 24 | val keystore = KeyStore.getInstance(KeyStore.getDefaultType) 25 | val inputStream = new FileInputStream(keystoreFile) 26 | try { 27 | keystore.load(inputStream, keystorePassword.toCharArray) 28 | } finally { 29 | inputStream.close() 30 | } 31 | keyManager.init(keystore,keyPassword.toCharArray) 32 | 33 | val truststore = KeyStore.getInstance(KeyStore.getDefaultType) 34 | val trustInputStream = new FileInputStream(truststoreFile) 35 | try { 36 | truststore.load(trustInputStream, truststorePassword.toCharArray) 37 | } finally { 38 | trustInputStream.close() 39 | } 40 | 41 | 42 | tmf.init(truststore) 43 | 44 | 45 | 46 | val sslContext = SSLContext.getInstance("TLSv1.2") 47 | sslContext.init(keyManager.getKeyManagers, tmf.getTrustManagers, new SecureRandom()) 48 | 49 | val hostnameVerifier: HostnameVerifier = new HostnameVerifier { 50 | override def verify(host: String, sslSession: SSLSession): Boolean = true 51 | } 52 | 53 | HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier) 54 | 55 | sslContext.getSocketFactory 56 | } 57 | 58 | def getConnection(url: String): HttpURLConnection = { 59 | Props.get("ssl_client_auth", "false") match { 60 | case "true" => { 61 | val httpsUrl = if (url.startsWith("https://")) url else url.replaceFirst("^http://", "https://") 62 | 63 | val connection = new URL(httpsUrl).openConnection().asInstanceOf[HttpsURLConnection] 64 | connection.setSSLSocketFactory(sSLSocketFactory) 65 | connection 66 | } 67 | case "false" => new URL(url).openConnection().asInstanceOf[HttpURLConnection] 68 | case errorValue => sys.error(s"obp_certificate_activate props should be true or false, current value is: $errorValue") 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/scala/code/snippet/CreateIncome.scala: -------------------------------------------------------------------------------- 1 | package code.snippet 2 | 3 | import code.Constant._ 4 | import code.lib.ObpAPI 5 | import code.lib.ObpAPI.{createIncome, getAccount, getBalancingTransaction} 6 | import code.util.Helper.{MdcLoggable, getAccountTitle} 7 | import net.liftweb.common.Box 8 | import net.liftweb.http.js.JE.Call 9 | import net.liftweb.http.js.JsCmd 10 | import net.liftweb.http.{RequestVar, S, SHtml} 11 | import net.liftweb.util.Helpers._ 12 | import net.liftweb.util.Props 13 | 14 | import scala.xml.NodeSeq 15 | 16 | 17 | class CreateIncome(params: List[String]) extends MdcLoggable { 18 | private object tagVar extends RequestVar("") 19 | val bankId = params(0) 20 | val accountId = params(1) 21 | val accountJson = getAccount(bankId, accountId, CUSTOM_OWNER_VIEW_ID).openOrThrowException("Could not open accountJson") 22 | def accountTitle = ".account-title *" #> getAccountTitle(accountJson) 23 | 24 | //set up ajax handlers to edit account label 25 | def addIncome(xhtml: NodeSeq): NodeSeq = { 26 | var incomeDescription = "" 27 | var incomeAmount = 0D 28 | val listOfTags: Seq[(String, String)] = S.?("income.tags"). 29 | split(",").toList.map(_.trim).map(i => i.replaceAll("_", "/")).map(i => (i,i)) 30 | 31 | def process(): JsCmd = { 32 | logger.debug(s"CreateIncome.addIncome.process: edit label $incomeDescription") 33 | val result = createIncome(bankId, accountId, incomeDescription, incomeAmount.toString, "EUR") 34 | if (result.isDefined) { 35 | val incomeAccountId = Props.get("incoming.account_id", "") 36 | val transactionId = result.map(_.transaction_id).getOrElse("") 37 | logger.debug(s"CreateIncome.addIncome.process.transactionId $transactionId") 38 | val creditTransactionId = getBalancingTransaction(transactionId) 39 | .map(_.credit_transaction.transaction_id).getOrElse("") 40 | logger.debug(s"CreateIncome.addIncome.process.creditTransactionId $creditTransactionId") 41 | val addTags = ObpAPI.addTags(bankId, accountId, "owner", creditTransactionId, List(tagVar.is)) 42 | logger.debug(s"CreateIncome.addIncome.process.addTags $addTags") 43 | val msg = "Saved" 44 | Call("socialFinanceNotifications.notify", msg).cmd 45 | S.redirectTo(s"/banks/$bankId/accounts/$accountId/owner") 46 | } else { 47 | val msg = s"Sorry, Income $incomeDescription could not be added ($result)" 48 | Call("socialFinanceNotifications.notifyError", msg).cmd 49 | } 50 | } 51 | 52 | ( 53 | "@income_description" #> SHtml.text("", s => incomeDescription = s) & 54 | "#income_category" #> SHtml.select(listOfTags, Box!! tagVar.is, tagVar(_)) & 55 | "@income_amount" #> SHtml.number(0D, (s:Double) => incomeAmount = s, 0D, 1000000000D, 0.01D) & 56 | // Replace the type=submit with Javascript that makes the ajax call. 57 | "type=submit" #> SHtml.ajaxSubmit(S.?("button.save"), process) 58 | ).apply(xhtml) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/webapp/banks/star/accounts/star/permissions/create.html: -------------------------------------------------------------------------------- 1 | 31 |
    32 | 75 |
    76 | -------------------------------------------------------------------------------- /src/main/webapp/banks/star/accounts/star/management.html: -------------------------------------------------------------------------------- 1 | 31 |
    32 | 64 | 65 |
    66 | -------------------------------------------------------------------------------- /src/main/scala/code/snippet/Login.scala: -------------------------------------------------------------------------------- 1 | /** 2 | Open Bank Project - Sofi Web Application 3 | Copyright (C) 2011 - 2021, TESOBE GmbH 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | 18 | Email: contact@tesobe.com 19 | TESOBE GmbH. 20 | Osloer Str. 16/17 21 | Berlin 13359, Germany 22 | 23 | This product includes software developed at 24 | TESOBE (http://www.tesobe.com/) 25 | by 26 | Simon Redfern : simon AT tesobe DOT com 27 | Stefan Bethge : stefan AT tesobe DOT com 28 | Everett Sochowski : everett AT tesobe DOT com 29 | Ayoub Benali: ayoub AT tesobe DOT com 30 | 31 | */ 32 | 33 | package code.snippet 34 | 35 | import code.Constant 36 | import code.lib.{OAuthClient, ObpAPI} 37 | import code.util.Helper.MdcLoggable 38 | import code.util.{Helper, Util} 39 | import net.liftweb.common.{Box, Full} 40 | import net.liftweb.http.js.JsCmd 41 | import net.liftweb.http.js.JsCmds.Noop 42 | import net.liftweb.http.provider.HTTPCookie 43 | import net.liftweb.http.{S, SHtml} 44 | import net.liftweb.util.Helpers._ 45 | 46 | class Login extends MdcLoggable { 47 | 48 | 49 | private def loggedIn = { 50 | // Correlated User ID Flow 51 | S.cookieValue(Constant.correlatedUserIdTargetCookieName) match { 52 | case Full(correlatedUserId) if correlatedUserId != null => 53 | // This will do the full correlatedUserFlow 54 | logger.debug("Expecting full correlatedUserFlow") 55 | Util.correlatedUserFlow(Some(correlatedUserId)) 56 | case _ => 57 | // This will do the partial correlatedUserFlow i.e. maybe add a customer and user customer link 58 | logger.debug("Expecting partial correlatedUserFlow") 59 | Util.correlatedUserFlow(None) 60 | } 61 | def getDisplayNameOfUser(): Box[String] = { 62 | ObpAPI.currentUser.map { 63 | u => 64 | u.provider.toLowerCase() match { 65 | case provider if provider.contains("google") => u.email 66 | case provider if provider.contains("yahoo") => u.email 67 | case _ => u.username 68 | } 69 | } 70 | } 71 | ".logged-out *" #> "" & 72 | "#logged-in-name *" #> getDisplayNameOfUser() & 73 | "#logout [onclick+]" #> SHtml.onEvent(s => { 74 | OAuthClient.logoutAll() 75 | Noop 76 | }) 77 | } 78 | 79 | def loggedOut = { 80 | ".logged-in *" #> "" & 81 | "#start-login [onclick]" #> { 82 | def actionJS: JsCmd = { 83 | OAuthClient.redirectToOauthLogin() 84 | Noop 85 | } 86 | SHtml.onEvent((s: String) => actionJS) 87 | } 88 | } 89 | 90 | def login = { 91 | if(OAuthClient.loggedIn) loggedIn 92 | else loggedOut 93 | } 94 | 95 | 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/webapp/media/js/toastr.min.js: -------------------------------------------------------------------------------- 1 | (function(n){n(["jquery"],function(n){return function(){function l(n,t,f){return u({type:r.error,iconClass:i().iconClasses.error,message:n,optionsOverride:f,title:t})}function a(n,t,f){return u({type:r.info,iconClass:i().iconClasses.info,message:n,optionsOverride:f,title:t})}function v(n){e=n}function y(n,t,f){return u({type:r.success,iconClass:i().iconClasses.success,message:n,optionsOverride:f,title:t})}function p(n,t,f){return u({type:r.warning,iconClass:i().iconClasses.warning,message:n,optionsOverride:f,title:t})}function w(r){var u=i();if(t||f(u),r&&n(":focus",r).length===0){r[u.hideMethod]({duration:u.hideDuration,easing:u.hideEasing,complete:function(){c(r)}});return}t.children().length&&t[u.hideMethod]({duration:u.hideDuration,easing:u.hideEasing,complete:function(){t.remove()}})}function b(){return{tapToDismiss:!0,toastClass:"toast",containerId:"toast-container",debug:!1,showMethod:"fadeIn",showDuration:300,showEasing:"swing",onShown:undefined,hideMethod:"fadeOut",hideDuration:1e3,hideEasing:"swing",onHidden:undefined,extendedTimeOut:1e3,iconClasses:{error:"toast-error",info:"toast-info",success:"toast-success",warning:"toast-warning"},iconClass:"toast-info",positionClass:"toast-top-right",timeOut:5e3,titleClass:"toast-title",messageClass:"toast-message",target:"body",closeHtml:" 50 |
    51 |
    52 | 53 |   54 | 55 |
    56 |
    57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 76 | 77 | 78 | 79 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 112 | 113 | 114 |
    Public
    71 | 72 | 73 | 74 | 75 |
    Visible to anyone (public) 80 |
    81 | 82 | 86 |
    87 |
    Descriptiondescription
    Metadata View
    Alias
    Permission name 104 |
    105 | 106 | 110 |
    111 |
    115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/main/webapp/banks/star/accounts/star/transactions/star/star.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | 36 | 37 | 38 |
    39 | 40 | 122 | 123 |
    124 | -------------------------------------------------------------------------------- /src/main/scala/code/lib/OAuthClient.scala: -------------------------------------------------------------------------------- 1 | /** 2 | Open Bank Project - Sofi Web Application 3 | Copyright (C) 2011 - 2021, TESOBE GmbH. 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | 18 | Email: contact@tesobe.com 19 | TESOBE GmbH. 20 | Osloer Str. 16/17 21 | Berlin 13359, Germany 22 | 23 | This product includes software developed at 24 | TESOBE (http://www.tesobe.com/) 25 | by 26 | Simon Redfern : simon AT tesobe DOT com 27 | Stefan Bethge : stefan AT tesobe DOT com 28 | Everett Sochowski : everett AT tesobe DOT com 29 | Ayoub Benali: ayoub AT tesobe DOT com 30 | 31 | */ 32 | 33 | package code.lib 34 | 35 | import code.util.Helper 36 | import code.util.Helper.MdcLoggable 37 | import net.liftweb.common.{Box, Empty, Failure, Full} 38 | import net.liftweb.http.{LiftResponse, S, SessionVar} 39 | import net.liftweb.util.Props 40 | import oauth.signpost.{OAuthConsumer, OAuthProvider} 41 | import oauth.signpost.basic.DefaultOAuthConsumer 42 | import oauth.signpost.signature.HmacSha256MessageSigner 43 | 44 | sealed trait Provider { 45 | val name : String 46 | 47 | val apiBaseUrl : String 48 | val requestTokenUrl : String 49 | val accessTokenUrl : String 50 | val authorizeUrl : String 51 | val signupUrl : Option[String] 52 | 53 | /** 54 | * Can't do oAuthProvider = new DefaultOAuthProvider(requestTokenUrl, accessTokenUrl, authorizeUrl) 55 | * here as the Strings all evaluate at null at this point in object creation 56 | */ 57 | val oAuthProvider : OAuthProvider 58 | 59 | val consumerKey : String 60 | val consumerSecret : String 61 | } 62 | 63 | trait DefaultProvider extends Provider { 64 | val name = "The Open Bank Project Demo" 65 | 66 | val baseUrl = Props.get("api_hostname", S.hostName) 67 | val oauthBaseUrlPortal = Props.get("api_portal_hostname").getOrElse(baseUrl) 68 | val apiBaseUrl = baseUrl + "/obp" 69 | val requestTokenUrl = baseUrl + "/oauth/initiate" 70 | val accessTokenUrl = baseUrl + "/oauth/token" 71 | val authorizeUrl = oauthBaseUrlPortal + "/oauth/authorize" 72 | val signupUrl = Some(baseUrl + "/user_mgt/sign_up") 73 | 74 | lazy val oAuthProvider : OAuthProvider = new ObpOAuthProvider(requestTokenUrl, accessTokenUrl, authorizeUrl) 75 | 76 | val consumerKey = Props.get("obp_consumer_key", "") 77 | val consumerSecret = Props.get("obp_secret_key", "") 78 | } 79 | 80 | object OBPDemo extends DefaultProvider 81 | 82 | object AddBankAccountProvider extends DefaultProvider { 83 | override val name = "The Open Bank Project Demo - Add Bank Account" 84 | 85 | //The "login" prefix before /oauth means that we will use the oauth flow that will ask the user 86 | //to connect a bank account 87 | override val requestTokenUrl = baseUrl + "/login/oauth/initiate" 88 | override val accessTokenUrl = baseUrl + "/login/oauth/token" 89 | override val authorizeUrl = baseUrl + "/login/oauth/authorize" 90 | } 91 | 92 | case class Consumer(consumerKey : String, consumerSecret : String) { 93 | val oAuthConsumer : OAuthConsumer = new DefaultOAuthConsumer(consumerKey, consumerSecret) 94 | } 95 | 96 | case class Credential(provider : Provider, consumer : OAuthConsumer, readyToSign : Boolean) 97 | 98 | object credentials extends SessionVar[Option[Credential]](None) 99 | object mostRecentLoginAttemptProvider extends SessionVar[Box[Provider]](Empty) 100 | 101 | object OAuthClient extends MdcLoggable { 102 | 103 | def getAuthorizedCredential() : Option[Credential] = { 104 | credentials.filter(_.readyToSign) 105 | } 106 | 107 | def currentApiBaseUrl : String = { 108 | getAuthorizedCredential().map(_.provider.apiBaseUrl).getOrElse(OBPDemo.apiBaseUrl) 109 | } 110 | 111 | def setNewCredential(provider : Provider) : Credential = { 112 | val consumer = new DefaultOAuthConsumer(provider.consumerKey, provider.consumerSecret) 113 | val credential = Credential(provider, consumer, false) 114 | 115 | credentials.set(Some(credential)) 116 | credential 117 | } 118 | 119 | def handleCallback(): Box[LiftResponse] = { 120 | 121 | val success = for { 122 | verifier <- S.param("oauth_verifier") ?~ "No oauth verifier found" 123 | provider <- mostRecentLoginAttemptProvider.get ?~ "No provider found for callback" 124 | consumer <- Box(credentials.map(_.consumer)) ?~ "No consumer found for callback" 125 | } yield { 126 | //after this, consumer is ready to sign requests 127 | provider.oAuthProvider.retrieveAccessToken(consumer, verifier) 128 | //update the session credentials 129 | val newCredential = Credential(provider, consumer, true) 130 | credentials.set(Some(newCredential)) 131 | } 132 | 133 | success match { 134 | case Full(_) => S.redirectTo("/") //TODO: Allow this redirect to be customised 135 | case Failure(msg, _, _) => logger.warn(msg) 136 | case _ => logger.warn("Something went wrong in an oauth callback and there was no error message set for it") 137 | } 138 | Empty 139 | } 140 | 141 | def redirectToOauthLogin() = { 142 | redirect(OBPDemo) 143 | } 144 | 145 | private def redirect(provider : Provider) = { 146 | mostRecentLoginAttemptProvider.set(Full(provider)) 147 | val credential = setNewCredential(provider) 148 | credential.consumer.setMessageSigner(new HmacSha256MessageSigner()) 149 | val authUrl = provider.oAuthProvider.retrieveRequestToken(credential.consumer, Props.get("base_url", S.hostName) + "/oauthcallback") 150 | S.redirectTo(authUrl) 151 | } 152 | 153 | def redirectToConnectBankAccount() = { 154 | redirect(AddBankAccountProvider) 155 | } 156 | 157 | def loggedIn : Boolean = credentials.map(_.readyToSign).getOrElse(false) 158 | 159 | def logoutAll() = { 160 | val apiExplorerHost = {Props.get("base_url", S.hostName)} 161 | val obpApiHost = { Props.get("api_portal_hostname").or(Props.get("api_hostname")).getOrElse("Unknown") } 162 | credentials.set(None) 163 | S.redirectTo(s"$obpApiHost/user_mgt/logout?redirect=$apiExplorerHost") 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/scala/code/widgets/CustomTableSorter.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * The difference between this and lift's TableSorter.scala is that this one will use a text extractor function that 3 | * will search a td for an element with class "text" and use that to sort on. This allows for markup in a td rather than 4 | * just plain strings. Requires jquery. If no "text" class is found in the table, it will just use the table cell element's innerHTML to 5 | * sort on. 6 | * 7 | */ 8 | 9 | /* 10 | * Copyright 2007-2010 WorldWide Conferencing, LLC 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | package code.widgets.tableSorter { 26 | 27 | import _root_.net.liftweb.http.ResourceServer 28 | import _root_.scala.xml.NodeSeq 29 | import _root_.net.liftweb.http.{LiftRules} 30 | import _root_.net.liftweb.http.js._ 31 | import JsCmds._ 32 | import JE._ 33 | import jquery.JqJE._ 34 | 35 | // types to ease the creation of a JsObj to configure the TableSorter plugin. 36 | trait TableSorterOption[T] { 37 | 38 | def toJsObj: JsObj 39 | 40 | } 41 | 42 | // Because of the whacky js api we have to deal with sorter options 43 | // being either a string specifying the name of the sorter or the boolean value 44 | // false in the case you want to disable the sorting. 45 | 46 | trait SorterOption[T] extends TableSorterOption[T] { 47 | val sorter: T 48 | } 49 | 50 | /** 51 | * This is used to create the special case of SorterOption where sorting is 52 | * disabled 53 | */ 54 | case class DisableSorting() extends SorterOption[Boolean]{ 55 | 56 | val sorter = false 57 | 58 | def toJsObj = JsObj("sorter" -> sorter) 59 | } 60 | 61 | // Allows the user to type stuff like Sorting.DSC to specify that a column should be sorted 62 | // decening instead of just a plain integer that the js api expects. 63 | object Sorting extends Enumeration { 64 | type Sorting = Value 65 | val ASC, DSC = Value 66 | } 67 | 68 | /** 69 | * Sorter is used to define how the TableSorter should sort the columns. The possible list 70 | * of build in sorters are: shortDate, usLongDate, percent, isoDate, url, ipAddress, currency, 71 | * digit, text, shortDate, time, metadata 72 | * 73 | */ 74 | case class Sorter(sorter: String) extends SorterOption[String] { 75 | def toJsObj = JsObj("sorter" -> sorter) 76 | } 77 | 78 | object CustomTableSorter { 79 | 80 | private val emptyJsObj = new JsObj { 81 | def props = Nil 82 | } 83 | 84 | 85 | def apply(selector: String): NodeSeq = renderOnLoad(selector, CustomTableSorter.options()) 86 | def apply(selector: String, options: String): NodeSeq = renderOnLoad(selector, options) 87 | 88 | /** 89 | * Initializes the widget. You have to call this in boot for the widget to work. 90 | */ 91 | def init() { 92 | ResourceServer.allow({ 93 | case "tablesorter" :: tail => true 94 | }) 95 | } 96 | 97 | import Sorting._ 98 | 99 | /** 100 | * Use this method to create a type-safe configuration JsObj for the 101 | * TableSorter. See http://tablesorter.com/docs/ for more information 102 | * about the possible configurations of the jQuery plugin. 103 | * 104 | * Example usage: TableSorter.options( 105 | * headers = (0, DisableSorting()) :: (3,Sorter("currency")) :: Nil, 106 | * sortList = (3,Sorting.DSC) :: Nil) 107 | * 108 | * @param headers A list of tuples of int * sorter options. the int is the column number. 109 | * The column number is indexed starting from 0 110 | * @param sortList A list of tuples of int * Sorting. the int is the column number. 111 | * Use DisableSorting to disable sorting 112 | * @return A JsObj with valid properties to configure the jQuery TableSorter plugin 113 | */ 114 | def options(headers: List[(Int, TableSorterOption[_])], 115 | widgets: List[String], 116 | sortList: List[(Int, Sorting)]): String = { 117 | 118 | val jsHeaders = headers 119 | .map{ case (index, header) => JsObj(index.toString -> header.toJsObj)} 120 | .foldLeft[JsObj](emptyJsObj)(_ +* _) 121 | val jSSortList = JsArray( sortList.map{ case (index, sorting) => JsArray(index,sorting.id)}:_*) 122 | val widgetsArr = JsArray ( widgets.map( Str(_) ):_* ) 123 | "{" + "sortList:" + jSSortList.toJsCmd + ",headers:" + jsHeaders.toJsCmd + ",widgets:" + widgetsArr.toJsCmd + ",textExtraction:" + 124 | """function(node){var sortOn = $(node).find(".text").first().html(); return sortOn? sortOn : node.innerHTML}""" + "}" 125 | } 126 | 127 | //Convenience versions of the options method that provide default values for all the arguments. 128 | def options(): String = options(Nil, List("zebra"), List((0, ASC))) 129 | 130 | def options(headers: List[(Int, TableSorterOption[_])], 131 | sortList: List[(Int, Sorting)]): String = options(headers, List("zebra"), sortList) 132 | 133 | /** 134 | * Transforms a regular table into a tablesorter when page is loaded 135 | * 136 | * @param selector A CSS selector for the table you want to transform 137 | * @param options A JsObject configuring the tablesorter. You can use the connivance method 138 | * TableSorter.options to create the JsObj in a type-safe manner. Check out 139 | http://tablesorter.com/docs/ for more info about the possible configurations. 140 | */ 141 | def renderOnLoad(selector: String, options: String): NodeSeq = { 142 | val onLoad = """jQuery(document).ready(function(){ 143 | jQuery('"""+selector+"""').tablesorter("""+options+""") 144 | });""" 145 | 146 | 147 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |