mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:07:02 +00:00
updated the API project files
This commit is contained in:
parent
b4b5655f0b
commit
cf1e83b5a3
7
.gitignore
vendored
7
.gitignore
vendored
@ -8,6 +8,7 @@
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
MavLift/.cache
|
||||
MavLift/src/main/resources/rebel.xml
|
||||
MavLift/src/main/resources/props
|
||||
.cache
|
||||
target
|
||||
MavLift/src/main/resources/
|
||||
MavLift/src/test/resources/
|
||||
3
MavLift/.gitignore
vendored
3
MavLift/.gitignore
vendored
@ -1,2 +1 @@
|
||||
target
|
||||
src/main/resources/
|
||||
|
||||
|
||||
614
MavLift/pom.xml
614
MavLift/pom.xml
@ -1,295 +1,347 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.tesobe</groupId>
|
||||
<artifactId>opan_bank</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>war</packaging>
|
||||
<name>Opan Bank</name>
|
||||
<inceptionYear>2011</inceptionYear>
|
||||
<properties>
|
||||
<scala.version>2.9.1</scala.version>
|
||||
<!-- Common plugin settings -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>${project.build.sourceEncoding}</project.reporting.outputEncoding>
|
||||
<!-- vscaladoc settings -->
|
||||
<maven.scaladoc.vscaladocVersion>1.2-m1</maven.scaladoc.vscaladocVersion>
|
||||
<vscaladoc.links.liftweb.pathsufix>scaladocs/</vscaladoc.links.liftweb.pathsufix>
|
||||
<vscaladoc.links.liftweb.baseurl>http://scala-tools.org/mvnsites/liftweb</vscaladoc.links.liftweb.baseurl>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype.releases</id>
|
||||
<name>sonatype Dependencies Repository for Releases</name>
|
||||
<url>https://oss.sonatype.org/content/groups/scala-tools</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sonatype.snapshots</id>
|
||||
<name>sonatype Dependencies Repository for Snapshots</name>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>scala-tools.releases</id>
|
||||
<name>Scala-Tools Dependencies Repository for Releases</name>
|
||||
<url>http://scala-tools.org/repo-releases</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>scala-tools.snapshots</id>
|
||||
<name>Scala-Tools Dependencies Repository for Snapshots</name>
|
||||
<url>http://scala-tools.org/repo-snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.tesobe</groupId>
|
||||
<artifactId>OBP-API</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>war</packaging>
|
||||
<name>Open Bank Project API</name>
|
||||
<inceptionYear>2011</inceptionYear>
|
||||
<properties>
|
||||
<scala.version>2.9.1</scala.version>
|
||||
<lift.version>2.4</lift.version>
|
||||
<!-- Common plugin settings -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>${project.build.sourceEncoding}</project.reporting.outputEncoding>
|
||||
<!-- vscaladoc settings -->
|
||||
<maven.scaladoc.vscaladocVersion>1.2-m1</maven.scaladoc.vscaladocVersion>
|
||||
<vscaladoc.links.liftweb.pathsufix>scaladocs/</vscaladoc.links.liftweb.pathsufix>
|
||||
<vscaladoc.links.liftweb.baseurl>http://scala-tools.org/mvnsites/liftweb</vscaladoc.links.liftweb.baseurl>
|
||||
</properties>
|
||||
|
||||
<pluginRepositories>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>scala-tools.releases</id>
|
||||
<name>Scala-Tools Dependencies Repository for Releases</name>
|
||||
<url>https://oss.sonatype.org/content/groups/scala-tools/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>java.net.maven2</id>
|
||||
<name>java.net Maven2 Repository</name>
|
||||
<url>http://download.java.net/maven/2/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>scala-tools.snapshots</id>
|
||||
<name>Scala-Tools Dependencies Repository for Snapshots</name>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>sonatype.releases</id>
|
||||
<name>sonatype Dependencies Repository for Releases</name>
|
||||
<url>https://oss.sonatype.org/content/groups/scala-tools</url>
|
||||
<id>org.sonatype.oss.groups.public</id>
|
||||
<name>Sonatype Public</name>
|
||||
<url>https://oss.sonatype.org/content/groups/public</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>scala-tools.releases</id>
|
||||
<name>Scala-Tools Plugins Repository for Releases</name>
|
||||
<url>http://scala-tools.org/repo-releases</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</pluginRepositories>
|
||||
|
||||
<dependencies>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.liftweb</groupId>
|
||||
<artifactId>lift-mapper_${scala.version}</artifactId>
|
||||
<version>${lift.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.liftweb</groupId>
|
||||
<artifactId>lift-widgets_${scala.version}</artifactId>
|
||||
<version>${lift.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.databinder</groupId>
|
||||
<artifactId>dispatch-http_${scala.version}</artifactId>
|
||||
<version>0.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.databinder</groupId>
|
||||
<artifactId>dispatch-oauth_${scala.version}</artifactId>
|
||||
<version>0.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.liftweb</groupId>
|
||||
<artifactId>lift-mapper_2.9.1</artifactId>
|
||||
<version>2.4-M4</version>
|
||||
<groupId>net.databinder</groupId>
|
||||
<artifactId>dispatch-lift-json_${scala.version}</artifactId>
|
||||
<version>0.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.liftweb</groupId>
|
||||
<artifactId>lift-widgets_2.9.1</artifactId>
|
||||
<version>2.4-M4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.databinder</groupId>
|
||||
<artifactId>dispatch-http_${scala.version}</artifactId>
|
||||
<version>0.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.databinder</groupId>
|
||||
<artifactId>dispatch-oauth_${scala.version}</artifactId>
|
||||
<version>0.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>0.9.26</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>8.4-701.jdbc4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.2.138</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scala-tools.testing</groupId>
|
||||
<artifactId>specs_2.9.1</artifactId>
|
||||
<version>1.6.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
<version>6.1.25</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpg-jdk16</artifactId>
|
||||
<version>1.46</version>
|
||||
</dependency>
|
||||
<!-- for LiftConsole -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>0.9.26</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>8.4-701.jdbc4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.2.138</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scalatest</groupId>
|
||||
<artifactId>scalatest_${scala.version}</artifactId>
|
||||
<version>2.0.M5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scala-tools.testing</groupId>
|
||||
<artifactId>specs_${scala.version}</artifactId>
|
||||
<version>1.6.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
<version>6.1.25</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpg-jdk16</artifactId>
|
||||
<version>1.46</version>
|
||||
</dependency>
|
||||
<!-- for LiftConsole -->
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-compiler</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-compiler</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
<scope>test</scope>
|
||||
<artifactId>scala-library</artifactId>
|
||||
<version>2.9.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.liftweb</groupId>
|
||||
<artifactId>lift-mongodb_2.9.1</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.liftweb</groupId>
|
||||
<artifactId>lift-mongodb-record_2.9.1</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>casbah_${scala.version}</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<scope>compile</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>net.liftweb</groupId>
|
||||
<artifactId>lift-mongodb_${scala.version}</artifactId>
|
||||
<version>${lift.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.liftweb</groupId>
|
||||
<artifactId>lift-mongodb-record_${scala.version}</artifactId>
|
||||
<version>${lift.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>casbah_${scala.version}</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<scope>compile</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main</sourceDirectory>
|
||||
<testSourceDirectory>src/test/scala</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
<version>2.9</version>
|
||||
<configuration>
|
||||
<charset>${project.build.sourceEncoding}</charset>
|
||||
<jvmArgs>
|
||||
<jvmArg>-Xmx1024m</jvmArg>
|
||||
<jvmArg>-DpackageLinkDefs=file://${project.build.directory}/packageLinkDefs.properties</jvmArg>
|
||||
</jvmArgs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>2.4.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-copy-resources</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<overwrite>true</overwrite>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src</directory>
|
||||
<includes>
|
||||
<include>packageLinkDefs.properties</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>maven-jetty-plugin</artifactId>
|
||||
<version>6.1.25</version>
|
||||
<configuration>
|
||||
<contextPath>/</contextPath>
|
||||
<scanIntervalSeconds>5</scanIntervalSeconds>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>net.sf.alchim</groupId>
|
||||
<artifactId>yuicompressor-maven-plugin</artifactId>
|
||||
<version>0.7.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compress</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<nosuffix>true</nosuffix>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-idea-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<configuration>
|
||||
<downloadSources>true</downloadSources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<downloadSources>true</downloadSources>
|
||||
<additionalProjectnatures>
|
||||
<projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
|
||||
</additionalProjectnatures>
|
||||
<additionalBuildcommands>
|
||||
<buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
|
||||
</additionalBuildcommands>
|
||||
<classpathContainers>
|
||||
<classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
|
||||
<classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
|
||||
</classpathContainers>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
<version>2.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>revision</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
|
||||
<generateGitPropertiesFile>true</generateGitPropertiesFile>
|
||||
<generateGitPropertiesFilename>src/main/resources/git.properties</generateGitPropertiesFilename>
|
||||
<failOnNoGitDirectory>false</failOnNoGitDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
<version>2.14.3</version>
|
||||
<configuration>
|
||||
<charset>${project.build.sourceEncoding}</charset>
|
||||
<jvmArgs>
|
||||
<jvmArg>-Xmx1024m</jvmArg>
|
||||
<jvmArg>-DpackageLinkDefs=file://${project.build.directory}/packageLinkDefs.properties</jvmArg>
|
||||
</jvmArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<build>
|
||||
<sourceDirectory>src/main/scala</sourceDirectory>
|
||||
<testSourceDirectory>src/test/scala</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<!-- enable the scalatest plugin -->
|
||||
<groupId>org.scalatest</groupId>
|
||||
<artifactId>maven-scalatest-plugin</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<configuration>
|
||||
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
|
||||
<junitxml>.</junitxml>
|
||||
<filereports>WDF TestSuite.txt</filereports>
|
||||
<argLine>-Drun.mode=test</argLine>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<!-- add src/main/java to source dirs -->
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src/main/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
<version>2.15.2</version>
|
||||
<configuration>
|
||||
<charset>${project.build.sourceEncoding}</charset>
|
||||
<jvmArgs>
|
||||
<jvmArg>-Xmx1024m</jvmArg>
|
||||
<jvmArg>-DpackageLinkDefs=file://${project.build.directory}/packageLinkDefs.properties</jvmArg>
|
||||
</jvmArgs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-copy-resources</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<overwrite>true</overwrite>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src</directory>
|
||||
<includes>
|
||||
<include>packageLinkDefs.properties</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>maven-jetty-plugin</artifactId>
|
||||
<version>6.1.25</version>
|
||||
<configuration>
|
||||
<contextPath>/</contextPath>
|
||||
<scanIntervalSeconds>5</scanIntervalSeconds>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>net.sf.alchim</groupId>
|
||||
<artifactId>yuicompressor-maven-plugin</artifactId>
|
||||
<version>0.7.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compress</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<nosuffix>true</nosuffix>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-idea-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<configuration>
|
||||
<downloadSources>true</downloadSources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<downloadSources>true</downloadSources>
|
||||
<additionalProjectnatures>
|
||||
<projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
|
||||
</additionalProjectnatures>
|
||||
<additionalBuildcommands>
|
||||
<buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
|
||||
</additionalBuildcommands>
|
||||
<classpathContainers>
|
||||
<classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
|
||||
<classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
|
||||
</classpathContainers>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
<version>2.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>revision</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
|
||||
<generateGitPropertiesFile>true</generateGitPropertiesFile>
|
||||
<generateGitPropertiesFilename>src/main/resources/git.properties</generateGitPropertiesFilename>
|
||||
<failOnNoGitDirectory>false</failOnNoGitDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
<version>2.15.2</version>
|
||||
<configuration>
|
||||
<charset>${project.build.sourceEncoding}</charset>
|
||||
<jvmArgs>
|
||||
<jvmArg>-Xmx1024m</jvmArg>
|
||||
<jvmArg>-DpackageLinkDefs=file://${project.build.directory}/packageLinkDefs.properties</jvmArg>
|
||||
</jvmArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</project>
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
#Project properties
|
||||
sbt.version=0.11.2
|
||||
sbt.version=0.11.3
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
|
||||
|
||||
import sbt._
|
||||
import Keys._
|
||||
import com.github.siasia._
|
||||
@ -9,9 +11,9 @@ object LiftProjectBuild extends Build {
|
||||
override lazy val settings = super.settings ++ buildSettings
|
||||
|
||||
lazy val buildSettings = Seq(
|
||||
organization := "com.tesobe",
|
||||
version := "0.1",
|
||||
scalaVersion := "2.9.1")
|
||||
organization := pom.groupId,
|
||||
version := pom.version
|
||||
)
|
||||
|
||||
def yourWebSettings = webSettings ++ Seq(
|
||||
// If you are use jrebel
|
||||
@ -19,40 +21,74 @@ object LiftProjectBuild extends Build {
|
||||
)
|
||||
|
||||
lazy val opanBank = Project(
|
||||
"OpanBank",
|
||||
pom.artifactId,
|
||||
base = file("."),
|
||||
settings = defaultSettings ++ yourWebSettings)
|
||||
settings = defaultSettings ++ yourWebSettings ++ pom.settings)
|
||||
|
||||
object pom {
|
||||
|
||||
val pomFile = "pom.xml"
|
||||
lazy val pom = xml.XML.loadFile(pomFile)
|
||||
|
||||
lazy val pomProperties = (for{
|
||||
props <- (pom \ "properties")
|
||||
p <- props.child
|
||||
} yield {
|
||||
p.label -> p.text
|
||||
}).toMap
|
||||
|
||||
private lazy val PropertiesExpr = """.*\$\{(.*?)\}.*""".r
|
||||
|
||||
def populateProps(t: String) = t match {
|
||||
case PropertiesExpr(p) => {
|
||||
val replaceWith = pomProperties.get(p)
|
||||
t.replace("${"+p+"}", replaceWith.getOrElse(throw new Exception("Cannot find property: '" + p + "' required by: '" + t + "' in: " + pomFile)))
|
||||
}
|
||||
case _ => t
|
||||
}
|
||||
|
||||
lazy val pomDeps = (for{
|
||||
dep <- pom \ "dependencies" \ "dependency"
|
||||
} yield {
|
||||
val scope = (dep \ "scope")
|
||||
val groupId = (dep \ "groupId").text
|
||||
val noScope = populateProps(groupId) % populateProps((dep \ "artifactId").text) % populateProps((dep \ "version").text)
|
||||
val nonCustom = if (scope.nonEmpty) noScope % populateProps(scope.text)
|
||||
else noScope
|
||||
|
||||
if (groupId.endsWith("jetty")) Seq(noScope % "container", nonCustom) //hack to add jetty deps in container scope as it is required by the web plugin
|
||||
else Seq(nonCustom)
|
||||
}).flatten
|
||||
|
||||
lazy val pomRepos = for {
|
||||
rep <- pom \ "repositories" \ "repository"
|
||||
} yield {
|
||||
populateProps((rep \ "url").text) at populateProps((rep \ "url").text)
|
||||
}
|
||||
|
||||
lazy val pomScalaVersion = (pom \ "properties" \ "scala.version").text
|
||||
|
||||
lazy val artifactId = (pom \ "artifactId").text
|
||||
lazy val groupId = (pom \ "groupId").text
|
||||
lazy val version = (pom \ "version").text
|
||||
lazy val name = (pom \ "name").text
|
||||
|
||||
lazy val settings = Seq(
|
||||
scalaVersion := pomScalaVersion,
|
||||
libraryDependencies ++= pomDeps,
|
||||
resolvers ++= pomRepos
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
lazy val defaultSettings = Defaults.defaultSettings ++ Seq(
|
||||
name := "Opan Bank",
|
||||
name := pom.name,
|
||||
resolvers ++= Seq(
|
||||
"Typesafe Repo" at "http://repo.typesafe.com/typesafe/releases",
|
||||
"Java.net Maven2 Repository" at "http://download.java.net/maven/2/",
|
||||
"Scala-Tools Dependencies Repository for Releases" at "http://scala-tools.org/repo-releases",
|
||||
"Scala-Tools Dependencies Repository for Snapshots" at "http://scala-tools.org/repo-snapshots"),
|
||||
|
||||
libraryDependencies ++= {
|
||||
val liftVersion = "2.4-M4"
|
||||
Seq(
|
||||
//%% means: add current scala version to artifact name
|
||||
|
||||
"net.liftweb" %% "lift-webkit" % liftVersion % "compile",
|
||||
"net.liftweb" %% "lift-mapper" % liftVersion % "compile",
|
||||
"net.liftweb" %% "lift-mongodb" % liftVersion % "compile",
|
||||
"net.liftweb" %% "lift-mongodb-record" % liftVersion % "compile",
|
||||
"net.liftweb" %% "lift-widgets" % liftVersion % "compile",
|
||||
// "org.eclipse.jetty" % "jetty-webapp" % "7.5.4.v20111024" % "container",
|
||||
// "org.eclipse.jetty" % "jetty-webapp" % "8.0.4.v20111024" % "container",
|
||||
"org.mortbay.jetty" % "jetty" % "6.1.22" % "container",
|
||||
"javax.servlet" % "servlet-api" % "2.5" % "provided->default",
|
||||
"ch.qos.logback" % "logback-classic" % "1.0.0" % "compile",
|
||||
"com.h2database" % "h2" % "1.2.138" % "runtime",
|
||||
"com.mongodb.casbah" %% "casbah" % "2.1.5-1" % "compile",
|
||||
"org.scalatest" %% "scalatest" % "1.6.1" % "test",
|
||||
"org.scala-tools.testing" %% "specs" % "1.6.9" % "test",
|
||||
"junit" % "junit" % "4.10" % "test")
|
||||
},
|
||||
|
||||
// compile options
|
||||
scalacOptions ++= Seq("-encoding", "UTF-8", "-deprecation", "-unchecked"),
|
||||
javacOptions ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"),
|
||||
|
||||
@ -13,6 +13,7 @@ libraryDependencies <+= sbtVersion(v => v match {
|
||||
case "0.11.0" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.0-0.2.8"
|
||||
case "0.11.1" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.1-0.2.10"
|
||||
case "0.11.2" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.2-0.2.11"
|
||||
case "0.11.3" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.3-0.2.11.1"
|
||||
})
|
||||
|
||||
//sbteclipse
|
||||
@ -22,7 +23,7 @@ resolvers += {
|
||||
Resolver.url("Typesafe Repository", typesafeRepoUrl)(pattern)
|
||||
}
|
||||
|
||||
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0")
|
||||
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0")
|
||||
|
||||
//sbt-idea
|
||||
resolvers += "sbt-idea-repo" at "http://mpeltonen.github.com/maven/"
|
||||
|
||||
321
MavLift/src/main/java/code/pgp/PgpEncryption.java
Normal file
321
MavLift/src/main/java/code/pgp/PgpEncryption.java
Normal file
@ -0,0 +1,321 @@
|
||||
package code.pgp;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openpgp.PGPCompressedData;
|
||||
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
|
||||
import org.bouncycastle.openpgp.PGPEncryptedData;
|
||||
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
|
||||
import org.bouncycastle.openpgp.PGPEncryptedDataList;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPLiteralData;
|
||||
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
|
||||
import org.bouncycastle.openpgp.PGPObjectFactory;
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPUtil;
|
||||
|
||||
/**
|
||||
* Simple routine to encrypt and decrypt using a Public and Private key with passphrase. This service
|
||||
* routine provides the basic PGP services between byte arrays.
|
||||
*
|
||||
*/
|
||||
public class PgpEncryption {
|
||||
|
||||
public PgpEncryption() {
|
||||
// Empty constructor
|
||||
}
|
||||
|
||||
private static PGPPrivateKey findSecretKey(
|
||||
PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass)
|
||||
throws PGPException, NoSuchProviderException {
|
||||
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
|
||||
|
||||
if (pgpSecKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return pgpSecKey.extractPrivateKey(pass, "BC");
|
||||
}
|
||||
|
||||
/**
|
||||
* decrypt the passed in message stream
|
||||
*
|
||||
* @param encrypted
|
||||
* The message to be decrypted.
|
||||
* @param passPhrase
|
||||
* Pass phrase (key)
|
||||
*
|
||||
* @return Clear text as a byte array. I18N considerations are not handled
|
||||
* by this routine
|
||||
* @exception IOException
|
||||
* @exception PGPException
|
||||
* @exception NoSuchProviderException
|
||||
*/
|
||||
public static byte[] decrypt(byte[] encrypted, InputStream keyIn, char[] password)
|
||||
throws IOException, PGPException, NoSuchProviderException {
|
||||
InputStream in = new ByteArrayInputStream(encrypted);
|
||||
|
||||
in = PGPUtil.getDecoderStream(in);
|
||||
|
||||
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
||||
PGPEncryptedDataList enc = null;
|
||||
Object o = pgpF.nextObject();
|
||||
|
||||
//
|
||||
// the first object might be a PGP marker packet.
|
||||
//
|
||||
if (o instanceof PGPEncryptedDataList) {
|
||||
enc = (PGPEncryptedDataList) o;
|
||||
} else {
|
||||
enc = (PGPEncryptedDataList) pgpF.nextObject();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// find the secret key
|
||||
//
|
||||
Iterator it = enc.getEncryptedDataObjects();
|
||||
PGPPrivateKey sKey = null;
|
||||
PGPPublicKeyEncryptedData pbe = null;
|
||||
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
|
||||
PGPUtil.getDecoderStream(keyIn));
|
||||
|
||||
while (sKey == null && it.hasNext()) {
|
||||
pbe = (PGPPublicKeyEncryptedData) it.next();
|
||||
|
||||
sKey = findSecretKey(pgpSec, pbe.getKeyID(), password);
|
||||
}
|
||||
|
||||
if (sKey == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"secret key for message not found.");
|
||||
}
|
||||
|
||||
InputStream clear = pbe.getDataStream(sKey, "BC");
|
||||
|
||||
|
||||
|
||||
PGPObjectFactory pgpFact = new PGPObjectFactory(clear);
|
||||
|
||||
PGPCompressedData cData = (PGPCompressedData) pgpFact.nextObject();
|
||||
|
||||
pgpFact = new PGPObjectFactory(cData.getDataStream());
|
||||
|
||||
PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
|
||||
|
||||
InputStream unc = ld.getInputStream();
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int ch;
|
||||
|
||||
while ((ch = unc.read()) >= 0) {
|
||||
out.write(ch);
|
||||
|
||||
}
|
||||
|
||||
byte[] returnBytes = out.toByteArray();
|
||||
out.close();
|
||||
return returnBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple PGP encryptor between byte[].
|
||||
*
|
||||
* @param clearData
|
||||
* The test to be encrypted
|
||||
* @param passPhrase
|
||||
* The pass phrase (key). This method assumes that the key is a
|
||||
* simple pass phrase, and does not yet support RSA or more
|
||||
* sophisiticated keying.
|
||||
* @param fileName
|
||||
* File name. This is used in the Literal Data Packet (tag 11)
|
||||
* which is really inly important if the data is to be related to
|
||||
* a file to be recovered later. Because this routine does not
|
||||
* know the source of the information, the caller can set
|
||||
* something here for file name use that will be carried. If this
|
||||
* routine is being used to encrypt SOAP MIME bodies, for
|
||||
* example, use the file name from the MIME type, if applicable.
|
||||
* Or anything else appropriate.
|
||||
*
|
||||
* @param armor
|
||||
*
|
||||
* @return encrypted data.
|
||||
* @exception IOException
|
||||
* @exception PGPException
|
||||
* @exception NoSuchProviderException
|
||||
*/
|
||||
public static byte[] encrypt(byte[] clearData, PGPPublicKey encKey,
|
||||
String fileName,boolean withIntegrityCheck, boolean armor)
|
||||
throws IOException, PGPException, NoSuchProviderException {
|
||||
if (fileName == null) {
|
||||
fileName = PGPLiteralData.CONSOLE;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
|
||||
|
||||
OutputStream out = encOut;
|
||||
if (armor) {
|
||||
out = new ArmoredOutputStream(out);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
|
||||
PGPCompressedDataGenerator.ZIP);
|
||||
OutputStream cos = comData.open(bOut); // open it with the final
|
||||
// destination
|
||||
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
|
||||
|
||||
// we want to generate compressed data. This might be a user option
|
||||
// later,
|
||||
// in which case we would pass in bOut.
|
||||
OutputStream pOut = lData.open(cos, // the compressed output stream
|
||||
PGPLiteralData.BINARY, fileName, // "filename" to store
|
||||
clearData.length, // length of clear data
|
||||
new Date() // current time
|
||||
);
|
||||
pOut.write(clearData);
|
||||
|
||||
lData.close();
|
||||
comData.close();
|
||||
|
||||
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(
|
||||
PGPEncryptedData.CAST5, withIntegrityCheck, new SecureRandom(),
|
||||
"BC");
|
||||
|
||||
cPk.addMethod(encKey);
|
||||
|
||||
byte[] bytes = bOut.toByteArray();
|
||||
|
||||
OutputStream cOut = cPk.open(out, bytes.length);
|
||||
|
||||
cOut.write(bytes); // obtain the actual bytes from the compressed stream
|
||||
|
||||
cOut.close();
|
||||
|
||||
out.close();
|
||||
|
||||
return encOut.toByteArray();
|
||||
}
|
||||
|
||||
private static PGPPublicKey readPublicKey(InputStream in)
|
||||
throws IOException, PGPException {
|
||||
in = PGPUtil.getDecoderStream(in);
|
||||
|
||||
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in);
|
||||
|
||||
//
|
||||
// we just loop through the collection till we find a key suitable for
|
||||
// encryption, in the real
|
||||
// world you would probably want to be a bit smarter about this.
|
||||
//
|
||||
|
||||
//
|
||||
// iterate through the key rings.
|
||||
//
|
||||
Iterator rIt = pgpPub.getKeyRings();
|
||||
|
||||
while (rIt.hasNext()) {
|
||||
PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next();
|
||||
Iterator kIt = kRing.getPublicKeys();
|
||||
|
||||
while (kIt.hasNext()) {
|
||||
PGPPublicKey k = (PGPPublicKey) kIt.next();
|
||||
|
||||
if (k.isEncryptionKey()) {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Can't find encryption key in key ring.");
|
||||
}
|
||||
|
||||
public static byte[] getBytesFromFile(File file) throws IOException {
|
||||
InputStream is = new FileInputStream(file);
|
||||
|
||||
// Get the size of the file
|
||||
long length = file.length();
|
||||
|
||||
if (length > Integer.MAX_VALUE) {
|
||||
// File is too large
|
||||
}
|
||||
|
||||
// Create the byte array to hold the data
|
||||
byte[] bytes = new byte[(int)length];
|
||||
|
||||
// Read in the bytes
|
||||
int offset = 0;
|
||||
int numRead = 0;
|
||||
while (offset < bytes.length
|
||||
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
|
||||
offset += numRead;
|
||||
}
|
||||
|
||||
// Ensure all the bytes have been read in
|
||||
if (offset < bytes.length) {
|
||||
throw new IOException("Could not completely read file "+file.getName());
|
||||
}
|
||||
|
||||
// Close the input stream and return bytes
|
||||
is.close();
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String encryptToFile(String inputStr, String keyFile, String outFile) throws Exception {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
byte[] original = inputStr.getBytes();
|
||||
|
||||
FileInputStream pubKey = new FileInputStream(keyFile);
|
||||
byte[] encrypted = encrypt(original, readPublicKey(pubKey), null,
|
||||
true, true);
|
||||
|
||||
FileOutputStream dfis = new FileOutputStream(outFile);
|
||||
dfis.write(encrypted);
|
||||
dfis.close();
|
||||
|
||||
return new String(encrypted);
|
||||
}
|
||||
|
||||
public static String decryptFromFile(String passphrase, String keyFile, String inputFile) throws Exception {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
byte[] encFromFile = getBytesFromFile(new File(inputFile));
|
||||
FileInputStream secKey = new FileInputStream(keyFile);
|
||||
|
||||
byte[] decrypted = decrypt(encFromFile, secKey, passphrase.toCharArray());
|
||||
|
||||
return new String(decrypted);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String encrypted = encryptToFile("Hello world","pub.asc","enc.asc");
|
||||
System.out.println("\nencrypted data = '" + new String(encrypted) + "'");
|
||||
|
||||
String decrypted = decryptFromFile("open sesame", "secret.asc", "enc.asc");
|
||||
System.out.println("\ndecrypted data = '" + decrypted + "'");
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -31,7 +31,7 @@ Berlin 13359, Germany
|
||||
*/
|
||||
package bootstrap.liftweb
|
||||
|
||||
import code.snippet._
|
||||
|
||||
import net.liftweb._
|
||||
import util._
|
||||
import common._
|
||||
@ -39,20 +39,18 @@ import http._
|
||||
import sitemap._
|
||||
import Loc._
|
||||
import mapper._
|
||||
import code.model.dataAccess.{MongoConfig,OBPUser,Privilege,Account, MongoDBLocalStorage, HostedAccount}
|
||||
import code.model.{Nonce, Consumer, Token}
|
||||
import code.model.traits.{Bank, View, ModeratedTransaction}
|
||||
import code.model.implementedTraits.{BankImpl, Anonymous, View}
|
||||
import com.tesobe.utils._
|
||||
import code.model.dataAccess._
|
||||
import code.model.{Nonce, Consumer, Token, Bank, ModeratedTransaction, View, BankAccount}
|
||||
import code.api._
|
||||
import net.liftweb.util.Helpers._
|
||||
import net.liftweb.widgets.tablesorter.TableSorter
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import code.snippet.OAuthHandshake
|
||||
import code.api.OAuthHandshake
|
||||
import net.liftweb.util.Schedule
|
||||
import net.liftweb.mongodb.BsonDSL._
|
||||
import code.model.dataAccess.LocalStorage
|
||||
import code.model.traits.BankAccount
|
||||
import net.liftweb.http.js.jquery.JqJsCmds
|
||||
import code.snippet.OAuthAuthorisation
|
||||
import net.liftweb.util.Helpers
|
||||
import javax.mail.{ Authenticator, PasswordAuthentication }
|
||||
/**
|
||||
* A class that's instantiated early and run. It allows the application
|
||||
@ -65,49 +63,74 @@ class Boot extends Loggable{
|
||||
MongoConfig.init
|
||||
|
||||
if (!DB.jndiJdbcConnAvailable_?) {
|
||||
val driver = Props.get("db.driver") openOr "org.h2.Driver"
|
||||
val vendor =
|
||||
new StandardDBVendor(driver,
|
||||
Props.get("db.url") openOr
|
||||
"jdbc:h2:lift_proto.db;AUTO_SERVER=TRUE",
|
||||
Props.get("db.user"), Props.get("db.password"))
|
||||
val driver =
|
||||
Props.mode match {
|
||||
case Props.RunModes.Production | Props.RunModes.Staging | Props.RunModes.Development => Props.get("db.driver") openOr "org.h2.Driver"
|
||||
case _ => "org.h2.Driver"
|
||||
}
|
||||
val vendor =
|
||||
Props.mode match {
|
||||
case Props.RunModes.Production | Props.RunModes.Staging | Props.RunModes.Development =>
|
||||
new StandardDBVendor(driver,
|
||||
Props.get("db.url") openOr "jdbc:h2:lift_proto.db;AUTO_SERVER=TRUE",
|
||||
Props.get("db.user"), Props.get("db.password"))
|
||||
case _ =>
|
||||
new StandardDBVendor(
|
||||
driver,
|
||||
"jdbc:h2:mem:OBPTest;DB_CLOSE_DELAY=-1",
|
||||
Empty, Empty)
|
||||
}
|
||||
|
||||
logger.debug("Using database driver: " + driver)
|
||||
LiftRules.unloadHooks.append(vendor.closeAllConnections_! _)
|
||||
|
||||
DB.defineConnectionManager(DefaultConnectionIdentifier, vendor)
|
||||
}
|
||||
Mailer.authenticator = for {
|
||||
Mailer.authenticator = for {
|
||||
user <- Props.get("mail.username")
|
||||
pass <- Props.get("mail.password")
|
||||
pass <- Props.get("mail.password")
|
||||
} yield new Authenticator {
|
||||
override def getPasswordAuthentication =
|
||||
new PasswordAuthentication(user,pass)
|
||||
}
|
||||
override def getPasswordAuthentication =
|
||||
new PasswordAuthentication(user,pass)
|
||||
}
|
||||
|
||||
val runningMode = Props.mode match {
|
||||
case Props.RunModes.Production => "Production mode"
|
||||
case Props.RunModes.Staging => "Staging mode"
|
||||
case Props.RunModes.Development => "Development mode"
|
||||
case Props.RunModes.Test => "test mode"
|
||||
case _ => "other mode"
|
||||
}
|
||||
|
||||
logger.info("running mode: " + runningMode)
|
||||
|
||||
// Use Lift's Mapper ORM to populate the database
|
||||
// you don't need to use Mapper to use Lift... use
|
||||
// any ORM you want
|
||||
Schemifier.schemify(true, Schemifier.infoF _, OBPUser, Privilege)
|
||||
Schemifier.schemify(true, Schemifier.infoF _, OBPUser, Privilege, Admin)
|
||||
|
||||
// where to search snippet
|
||||
LiftRules.addToPackages("code")
|
||||
|
||||
// For some restful stuff
|
||||
LiftRules.statelessDispatchTable.append(OBPRest) // stateless -- no session created
|
||||
|
||||
//OAuth API call
|
||||
LiftRules.dispatch.append(OAuthHandshake)
|
||||
LiftRules.statelessDispatchTable.append(OAuthHandshake)
|
||||
LiftRules.statelessDispatchTable.append(v1_0.OBPAPI1_0)
|
||||
LiftRules.statelessDispatchTable.append(v1_1.OBPAPI1_1)
|
||||
LiftRules.statelessDispatchTable.append(v1_2.OBPAPI1_2)
|
||||
LiftRules.statelessDispatchTable.append(ImporterAPI)
|
||||
LiftRules.statelessDispatchTable.append(CashAccountAPI)
|
||||
LiftRules.statelessDispatchTable.append(BankMockAPI)
|
||||
|
||||
//OAuth Mapper
|
||||
//OAuth API call
|
||||
LiftRules.statelessDispatchTable.append(OAuthHandshake)
|
||||
|
||||
//OAuth Mapper
|
||||
Schemifier.schemify(true, Schemifier.infoF _, Nonce)
|
||||
Schemifier.schemify(true, Schemifier.infoF _, Token)
|
||||
Schemifier.schemify(true, Schemifier.infoF _, Consumer)
|
||||
Schemifier.schemify(true, Schemifier.infoF _, Consumer)
|
||||
Schemifier.schemify(true, Schemifier.infoF _, HostedAccount)
|
||||
//lunch the scheduler to clean the database from the expired tokens and nonces
|
||||
Schedule.schedule(()=> OAuthHandshake.dataBaseCleaner, 2 minutes)
|
||||
|
||||
//launch the scheduler to clean the database from the expired tokens and nonces
|
||||
Schedule.schedule(()=> OAuthAuthorisation.dataBaseCleaner, 2 minutes)
|
||||
|
||||
def check(bool: Boolean) : Box[LiftResponse] = {
|
||||
if(bool){
|
||||
Empty
|
||||
@ -115,91 +138,94 @@ class Boot extends Loggable{
|
||||
Full(PlainTextResponse("unauthorized"))
|
||||
}
|
||||
}
|
||||
|
||||
def getTransactionsAndView (URLParameters : List[String]) : Box[(List[ModeratedTransaction], View)] =
|
||||
|
||||
def getTransactionsAndView (URLParameters : List[String]) : Box[(List[ModeratedTransaction], View, BankAccount)] =
|
||||
{
|
||||
val bank = URLParameters(0)
|
||||
val account = URLParameters(1)
|
||||
val viewName = URLParameters(2)
|
||||
|
||||
val transactionsAndView : Box[(List[ModeratedTransaction], View)] = for {
|
||||
b <- BankAccount(bank, account) ?~ {"account " + account + " not found for bank " + bank}
|
||||
v <- View.fromUrl(viewName) ?~ {"view " + viewName + " not found for account " + account + " and bank " + bank}
|
||||
if(b.authorisedAccess(v, OBPUser.currentUser))
|
||||
} yield (b.getModeratedTransactions(v.moderate), v)
|
||||
|
||||
val transactionsAndView : Box[(List[ModeratedTransaction], View, BankAccount)] = for {
|
||||
b <- BankAccount(bank, account) ?~ {"account " + account + " not found for bank " + bank}
|
||||
v <- View.fromUrl(viewName) ?~ {"view " + viewName + " not found for account " + account + " and bank " + bank}
|
||||
transactions <- b.getModeratedTransactions(OBPUser.currentUser, v)
|
||||
} yield (transactions, v, b)
|
||||
|
||||
transactionsAndView match {
|
||||
case Failure(msg, _, _) => logger.info("Could not get transactions and view: " + msg)
|
||||
case Failure(msg, _, _) => logger.warn("Could not get transactions and view: " + msg)
|
||||
case _ => //don't log anything
|
||||
}
|
||||
transactionsAndView
|
||||
}
|
||||
|
||||
def getAccount(URLParameters : List[String]) =
|
||||
|
||||
def getAccount(URLParameters : List[String]) =
|
||||
{
|
||||
val bankUrl = URLParameters(0)
|
||||
val accountUrl = URLParameters(1)
|
||||
val account = for {
|
||||
account <- LocalStorage.getAccount(bankUrl,accountUrl) ?~ {"account " + accountUrl + " not found for bank " + bankUrl}
|
||||
bank <- HostedBank.find("permalink",bankUrl)
|
||||
account <- bank.getAccount(accountUrl)
|
||||
user <- OBPUser.currentUser ?~ {"user not found when attempting to access account " + account + " of bank " + bankUrl}
|
||||
bankAccount <- BankAccount(bankUrl, accountUrl) ?~ {"account " + account + " not found for bank " + bankUrl}
|
||||
if(user.hasMangementAccess(bankAccount))
|
||||
if(user.hasMangementAccess(Account toBankAccount account))
|
||||
} yield account
|
||||
|
||||
|
||||
account match {
|
||||
case Failure(msg, _, _) => logger.info("Could not get account: " + msg)
|
||||
case _ => //don't log anything
|
||||
}
|
||||
account
|
||||
}
|
||||
def getTransaction(URLParameters : List[String]) =
|
||||
def getTransaction(URLParameters : List[String]) =
|
||||
{
|
||||
if(URLParameters.length==4)
|
||||
{
|
||||
if(URLParameters.length==4){
|
||||
val bank = URLParameters(0)
|
||||
val account = URLParameters(1)
|
||||
val transactionID = URLParameters(2)
|
||||
val viewName = URLParameters(3)
|
||||
val transaction = for{
|
||||
bankAccount <- BankAccount(bank, account) ?~ {"account " + account + " not found for bank " + bank}
|
||||
transaction <- bankAccount.transaction(transactionID) ?~ {"transaction " + transactionID + " not found in account " + account + " for bank " + bank}
|
||||
view <- View.fromUrl(viewName) ?~ {"view " + viewName + " not found"}
|
||||
if(bankAccount.authorisedAccess(view, OBPUser.currentUser))
|
||||
} yield (view.moderate(transaction),view)
|
||||
|
||||
transaction match {
|
||||
case Failure(msg, _, _) => logger.info("Could not get transaction: " + msg)
|
||||
case _ => //don't log anything
|
||||
}
|
||||
transaction
|
||||
bankAccount <- BankAccount(bank, account) ?~ {"account " + account + " not found for bank " + bank}
|
||||
view <- View.fromUrl(viewName)
|
||||
transaction <- bankAccount.moderatedTransaction(transactionID, view, OBPUser.currentUser)
|
||||
} yield (transaction,view)
|
||||
|
||||
transaction match {
|
||||
case Failure(msg, _, _) => logger.info("Could not get transaction: " + msg)
|
||||
case _ => //don't log anything
|
||||
}
|
||||
|
||||
transaction
|
||||
}
|
||||
else
|
||||
Empty
|
||||
}
|
||||
}
|
||||
// Build SiteMap
|
||||
val sitemap = List(
|
||||
Menu.i("Home") / "index",
|
||||
Menu.i("Privilege Admin") / "admin" / "privilege" >> TestAccess(() => {
|
||||
check(OBPUser.loggedIn_?)
|
||||
}) >> LocGroup("admin")
|
||||
}) >> LocGroup("admin")
|
||||
submenus(Privilege.menus : _*),
|
||||
Menu.i("OAuth") / "oauth" / "authorize", //OAuth authorization page
|
||||
Menu.i("Connect") / "connect",
|
||||
Menu.i("Consumer Admin") / "admin" / "consumers" >> LocGroup("admin")
|
||||
submenus(Consumer.menus : _*),
|
||||
Menu("Consumer Registration", "Developers") / "consumer-registration",
|
||||
Menu.i("Metrics") / "metrics",
|
||||
Menu.i("OAuth") / "oauth" / "authorize", //OAuth authorization page
|
||||
Menu.i("Connect") / "connect",
|
||||
|
||||
Menu.i("Banks") / "banks", //no test => list of open banks
|
||||
//list of open banks (banks with a least a bank account with an open account)
|
||||
Menu.param[Bank]("Bank", "bank", LocalStorage.getBank _ , bank => bank.id ) / "banks" / * ,
|
||||
//list of open accounts in a specific bank
|
||||
Menu.param[Bank]("Accounts", "accounts", LocalStorage.getBank _ , bank => bank.id ) / "banks" / * / "accounts",
|
||||
|
||||
Menu.param[Bank]("Accounts", "accounts", LocalStorage.getBank _ , bank => bank.id ) / "banks" / * / "accounts",
|
||||
|
||||
//test if the bank exists and if the user have access to management page
|
||||
Menu.params[Account]("Management", "management", getAccount _ , t => List("")) / "banks" / * / "accounts" / * / "management",
|
||||
|
||||
Menu.params[(List[ModeratedTransaction], View)]("Bank Account", "bank accounts", getTransactionsAndView _ , t => List("") )
|
||||
|
||||
Menu.params[(List[ModeratedTransaction], View, BankAccount)]("Bank Account", "bank accounts", getTransactionsAndView _ , t => List("") )
|
||||
/ "banks" / * / "accounts" / * / *,
|
||||
|
||||
Menu.params[(ModeratedTransaction,View)]("transaction", "transaction", getTransaction _ , t => List("") )
|
||||
/ "banks" / * / "accounts" / * / "transactions" / * / *
|
||||
Menu.params[(ModeratedTransaction,View)]("transaction", "transaction", getTransaction _ , t => List("") )
|
||||
/ "banks" / * / "accounts" / * / "transactions" / * / *
|
||||
)
|
||||
|
||||
def sitemapMutators = OBPUser.sitemapMutator
|
||||
@ -213,7 +239,7 @@ class Boot extends Loggable{
|
||||
//Show the spinny image when an Ajax call starts
|
||||
LiftRules.ajaxStart =
|
||||
Full(() => LiftRules.jsArtifacts.show("ajax-loader").cmd)
|
||||
|
||||
|
||||
// Make the spinny image go away when it ends
|
||||
LiftRules.ajaxEnd =
|
||||
Full(() => LiftRules.jsArtifacts.hide("ajax-loader").cmd)
|
||||
@ -226,32 +252,33 @@ class Boot extends Loggable{
|
||||
|
||||
// Use HTML5 for rendering
|
||||
LiftRules.htmlProperties.default.set((r: Req) =>
|
||||
new Html5Properties(r.userAgent))
|
||||
new Html5Properties(r.userAgent))
|
||||
|
||||
LiftRules.explicitlyParsedSuffixes = Helpers.knownSuffixes &~ (Set("com"))
|
||||
|
||||
// Make a transaction span the whole HTTP request
|
||||
S.addAround(DB.buildLoanWrapper)
|
||||
|
||||
|
||||
TableSorter.init
|
||||
|
||||
/**
|
||||
* A temporary measure to make sure there is an owner for the account, so that someone can set permissions
|
||||
*/
|
||||
Account.find(("holder", "Music Pictures Limited")) match{
|
||||
case Full(a) =>
|
||||
Account.find(("holder", "MUSIC PICTURES LIMITED")) match{
|
||||
case Full(a) =>
|
||||
HostedAccount.find(By(HostedAccount.accountID,a.id.toString)) match {
|
||||
case Empty => {
|
||||
val hostedAccount = HostedAccount.create.accountID(a.id.toString).saveMe
|
||||
case Empty => {
|
||||
val hostedAccount = HostedAccount.create.accountID(a.id.toString).saveMe
|
||||
logger.debug("Creating tesobe account user and granting it owner permissions")
|
||||
//create one
|
||||
// val randomPassword = StringHelpers.randomString(12)
|
||||
// println ("The admin password is :"+randomPassword )
|
||||
val userEmail = "tesobe@tesobe.com"
|
||||
val firstName = "tesobe first name"
|
||||
val lastName = "tesobe last name"
|
||||
val lastName = "tesobe last name"
|
||||
val theUserOwner = OBPUser.find(By(OBPUser.email, userEmail)).getOrElse(OBPUser.create.email(userEmail).password("123tesobe456").validated(true).firstName(firstName).lastName(lastName).saveMe)
|
||||
Privilege.create.account(hostedAccount).ownerPermission(true).user(theUserOwner).saveMe
|
||||
}
|
||||
case Full(hostedAccount) =>
|
||||
Privilege.create.account(hostedAccount).ownerPermission(true).user(theUserOwner).saveMe
|
||||
}
|
||||
case Full(hostedAccount) =>
|
||||
Privilege.find(By(Privilege.account,hostedAccount), By(Privilege.ownerPermission, true)) match{
|
||||
case Empty => {
|
||||
//create one
|
||||
@ -263,14 +290,14 @@ class Boot extends Loggable{
|
||||
val theUserOwner = OBPUser.find(By(OBPUser.email, userEmail)).getOrElse(OBPUser.create.email(userEmail).password("123tesobe456").validated(true).firstName(firstName).lastName(lastName).saveMe)
|
||||
Privilege.create.account(hostedAccount).ownerPermission(true)
|
||||
.mangementPermission(true).authoritiesPermission(true).boardPermission(true)
|
||||
.teamPermission(true).ourNetworkPermission(true).user(theUserOwner).saveMe
|
||||
.teamPermission(true).ourNetworkPermission(true).user(theUserOwner).saveMe
|
||||
}
|
||||
case _ => logger.debug("Owner privilege already exists")
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
case _ => logger.debug("No account found")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
405
MavLift/src/main/scala/code/api/OBPAPI1.0.scala
Normal file
405
MavLift/src/main/scala/code/api/OBPAPI1.0.scala
Normal file
@ -0,0 +1,405 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.api.v1_0
|
||||
|
||||
import code.actors.EnvelopeInserter
|
||||
import net.liftweb.http._
|
||||
import net.liftweb.http.rest._
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.Printer._
|
||||
import net.liftweb.json.Extraction._
|
||||
import net.liftweb.json.JsonAST._
|
||||
import java.util.Calendar
|
||||
import net.liftweb.common.Failure
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.common.Empty
|
||||
import net.liftweb.mongodb._
|
||||
import net.liftweb.json.JsonAST.JString
|
||||
import com.mongodb.casbah.Imports._
|
||||
import _root_.java.math.MathContext
|
||||
import org.bson.types._
|
||||
import org.joda.time.{ DateTime, DateTimeZone }
|
||||
import java.util.regex.Pattern
|
||||
import _root_.net.liftweb.common._
|
||||
import _root_.net.liftweb.util._
|
||||
import _root_.net.liftweb.http._
|
||||
import _root_.net.liftweb.mapper._
|
||||
import _root_.net.liftweb.util.Helpers._
|
||||
import _root_.net.liftweb.sitemap._
|
||||
import _root_.scala.xml._
|
||||
import _root_.net.liftweb.http.S._
|
||||
import _root_.net.liftweb.http.RequestVar
|
||||
import _root_.net.liftweb.util.Helpers._
|
||||
import _root_.net.liftweb.common.Full
|
||||
import net.liftweb.mongodb.{ Skip, Limit }
|
||||
import _root_.net.liftweb.http.S._
|
||||
import _root_.net.liftweb.mapper.view._
|
||||
import com.mongodb._
|
||||
import code.model.dataAccess.{ Account, OBPEnvelope, OBPUser,APIMetric, HostedAccount, LocalStorage}
|
||||
import code.model.{ModeratedTransaction, ModeratedBankAccount, View, BankAccount, Public, Bank, User}
|
||||
import code.model.dataAccess.OBPEnvelope._
|
||||
import java.util.Date
|
||||
import code.api.OAuthHandshake._
|
||||
import net.liftweb.util.Helpers.now
|
||||
import net.liftweb.json.Extraction
|
||||
import _root_.net.liftweb.json.Serialization
|
||||
import net.liftweb.json.NoTypeHints
|
||||
|
||||
case class APICallAmount(
|
||||
url: String,
|
||||
amount: Int
|
||||
)
|
||||
case class APICallAmounts(
|
||||
stats : List[APICallAmount]
|
||||
)
|
||||
|
||||
|
||||
case class APICallsForDay(
|
||||
amount : Int,
|
||||
date : Date
|
||||
)
|
||||
case class APICallsPerDay(
|
||||
stats : List[APICallsForDay]
|
||||
)
|
||||
|
||||
object OBPAPI1_0 extends RestHelper with Loggable {
|
||||
|
||||
implicit val _formats = Serialization.formats(NoTypeHints)
|
||||
|
||||
val dateFormat = ModeratedTransaction.dateFormat
|
||||
|
||||
private def getOBPUser(httpCode : Int, tokenID : Box[String]) : Box[OBPUser] =
|
||||
if(httpCode==200)
|
||||
{
|
||||
import code.model.Token
|
||||
Token.find(By(Token.key, tokenID.get)) match {
|
||||
case Full(token) => tryo{
|
||||
token.userId.get.toLong
|
||||
} match {
|
||||
case Full(id) => OBPUser.find(By(OBPUser.id, id))
|
||||
case _ => Empty
|
||||
}
|
||||
case _ => Empty
|
||||
}
|
||||
}
|
||||
else
|
||||
Empty
|
||||
|
||||
private def logAPICall =
|
||||
APIMetric.createRecord.
|
||||
url(S.uriAndQueryString.getOrElse("")).
|
||||
date((now: TimeSpan)).
|
||||
save
|
||||
|
||||
serve("obp" / "v1.0" prefix {
|
||||
|
||||
case Nil JsonGet json => {
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
def gitCommit : String = {
|
||||
val commit = tryo{
|
||||
val properties = new java.util.Properties()
|
||||
properties.load(getClass().getClassLoader().getResourceAsStream("git.properties"))
|
||||
properties.getProperty("git.commit.id", "")
|
||||
}
|
||||
commit getOrElse ""
|
||||
}
|
||||
|
||||
val apiDetails = {
|
||||
("api" ->
|
||||
("version" -> "1.0") ~
|
||||
("git_commit" -> gitCommit) ~
|
||||
("hosted_by" ->
|
||||
("organisation" -> "TESOBE") ~
|
||||
("email" -> "contact@tesobe.com") ~
|
||||
("phone" -> "+49 (0)30 8145 3994"))) ~
|
||||
("links" ->
|
||||
("rel" -> "banks") ~
|
||||
("href" -> "/banks") ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> "Returns a list of banks supported on this server"))
|
||||
}
|
||||
|
||||
JsonResponse(apiDetails)
|
||||
}
|
||||
|
||||
case bankAlias :: "accounts" :: accountAlias :: "transactions" :: viewName :: Nil JsonGet json => {
|
||||
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
import code.api.OAuthHandshake._
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
|
||||
def asInt(s: Box[String], default: Int): Int = {
|
||||
s match {
|
||||
case Full(str) => tryo { str.toInt } getOrElse default
|
||||
case _ => default
|
||||
}
|
||||
}
|
||||
val limit = asInt(json.header("obp_limit"), 50)
|
||||
val offset = asInt(json.header("obp_offset"), 0)
|
||||
/**
|
||||
* sortBy is currently disabled as it would open up a security hole:
|
||||
*
|
||||
* sortBy as currently implemented will take in a parameter that searches on the mongo field names. The issue here
|
||||
* is that it will sort on the true value, and not the moderated output. So if a view is supposed to return an alias name
|
||||
* rather than the true value, but someone uses sortBy on the other bank account name/holder, not only will the returned data
|
||||
* have the wrong order, but information about the true account holder name will be exposed due to its position in the sorted order
|
||||
*
|
||||
* This applies to all fields that can have their data concealed... which in theory will eventually be most/all
|
||||
*
|
||||
*/
|
||||
//val sortBy = json.header("obp_sort_by")
|
||||
val sortBy = None
|
||||
val sortDirection = OBPOrder(json.header("obp_sort_by"))
|
||||
val fromDate = tryo{dateFormat.parse(json.header("obp_from_date") getOrElse "")}.map(OBPFromDate(_))
|
||||
val toDate = tryo{dateFormat.parse(json.header("obp_to_date") getOrElse "")}.map(OBPToDate(_))
|
||||
|
||||
val basicParams = List(OBPLimit(limit),
|
||||
OBPOffset(offset),
|
||||
OBPOrdering(sortBy, sortDirection))
|
||||
val params : List[OBPQueryParam] = fromDate.toList ::: toDate.toList ::: basicParams
|
||||
val response = for {
|
||||
bankAccount <- BankAccount(bankAlias, accountAlias)
|
||||
view <- View.fromUrl(viewName)
|
||||
transactions <- bankAccount.getModeratedTransactions(getOBPUser(httpCode,oAuthParameters.get("oauth_token")), view, params : _*)
|
||||
} yield {
|
||||
JsonResponse("transactions" -> transactions.map(t => t.toJson(view)))
|
||||
}
|
||||
|
||||
response getOrElse InMemoryResponse(data.getBytes, headers, Nil, 401) : LiftResponse
|
||||
}
|
||||
|
||||
case bankAlias :: "accounts" :: accountAlias :: "transactions" ::
|
||||
transactionID :: "transaction" :: viewName :: Nil JsonGet json => {
|
||||
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val user = getOBPUser(httpCode,oAuthParameters.get("oauth_token"))
|
||||
|
||||
val moderatedTransactionAndView = for {
|
||||
bank <- Bank(bankAlias) ?~ { "bank " + bankAlias + " not found"} ~> 404
|
||||
account <- BankAccount(bankAlias, accountAlias) ?~ { "account " + accountAlias + " not found for bank"} ~> 404
|
||||
view <- View.fromUrl(viewName) ?~ { "view " + viewName + " not found for account"} ~> 404
|
||||
moderatedTransaction <- account.moderatedTransaction(transactionID, view, user) ?~ "view/transaction not authorised" ~> 401
|
||||
} yield {
|
||||
(moderatedTransaction, view)
|
||||
}
|
||||
|
||||
val links : List[JObject] = Nil
|
||||
|
||||
moderatedTransactionAndView.map(mtAndView => JsonResponse(("transaction" -> mtAndView._1.toJson(mtAndView._2)) ~
|
||||
("links" -> links)))
|
||||
}
|
||||
|
||||
case bankAlias :: "accounts" :: accountAlias :: "transactions" ::
|
||||
transactionID :: "comments" :: viewName :: Nil JsonGet json => {
|
||||
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val user = getOBPUser(httpCode,oAuthParameters.get("oauth_token"))
|
||||
|
||||
val comments = for {
|
||||
bank <- Bank(bankAlias) ?~ { "bank " + bankAlias + " not found"} ~> 404
|
||||
account <- BankAccount(bankAlias, accountAlias) ?~ { "account " + accountAlias + " not found for bank"} ~> 404
|
||||
view <- View.fromUrl(viewName) ?~ { "view " + viewName + " not found for account"} ~> 404
|
||||
moderatedTransaction <- account.moderatedTransaction(transactionID, view, user) ?~ "view/transaction not authorised" ~> 401
|
||||
comments <- Box(moderatedTransaction.metadata).flatMap(_.comments) ?~ "transaction metadata not authorised" ~> 401
|
||||
} yield comments
|
||||
|
||||
val links : List[JObject] = Nil
|
||||
|
||||
comments.map(cs => JsonResponse(("comments" -> cs.map(_.toJson)) ~
|
||||
("links" -> links)))
|
||||
}
|
||||
|
||||
case bankPermalink :: "accounts" :: Nil JsonGet json => {
|
||||
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
val user = getOBPUser(httpCode,oAuthParameters.get("oauth_token"))
|
||||
|
||||
def bankAccountSet2JsonResponse(bankAccounts: Set[BankAccount]): LiftResponse = {
|
||||
val accJson = bankAccounts.map(bAcc => bAcc.overviewJson(user))
|
||||
JsonResponse(("accounts" -> accJson))
|
||||
}
|
||||
|
||||
Bank(bankPermalink) match {
|
||||
case Full(bank) =>
|
||||
{
|
||||
if(httpCode == 200)
|
||||
{
|
||||
bank.accounts(user) match {
|
||||
case Full(a) => bankAccountSet2JsonResponse(a.toSet)
|
||||
case _ => InMemoryResponse("no account found".getBytes, Nil, Nil, 404)
|
||||
}
|
||||
}
|
||||
else
|
||||
InMemoryResponse(data.getBytes, Nil, Nil, httpCode)
|
||||
}
|
||||
case _ => {
|
||||
val error = "bank " + bankPermalink + " not found"
|
||||
InMemoryResponse(error.getBytes(), headers, Nil, 404)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case bankAlias :: "accounts" :: accountAlias :: "account" :: viewName :: Nil JsonGet json => {
|
||||
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
val user = getOBPUser(httpCode,oAuthParameters.get("oauth_token"))
|
||||
|
||||
case class ModeratedAccountAndViews(account: ModeratedBankAccount, views: Set[View])
|
||||
|
||||
val moderatedAccountAndViews = for {
|
||||
bank <- Bank(bankAlias) ?~ { "bank " + bankAlias + " not found"} ~> 404
|
||||
account <- BankAccount(bankAlias, accountAlias) ?~ { "account " + accountAlias + " not found for bank"} ~> 404
|
||||
view <- View.fromUrl(viewName) ?~ { "view " + viewName + " not found for account"} ~> 404
|
||||
moderatedAccount <- account.moderatedBankAccount(view, user) ?~ {"view/account not authorised"} ~> 401
|
||||
availableViews <- Full(account.permittedViews(user))
|
||||
} yield ModeratedAccountAndViews(moderatedAccount, availableViews)
|
||||
|
||||
def linkJson(view: View): JObject = {
|
||||
("rel" -> view.name) ~
|
||||
("href" -> { "/" + bankAlias + "/accounts/" + accountAlias + "/transactions/" + view.permalink }) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> view.description)
|
||||
}
|
||||
|
||||
def bankAccountMetaData(mv : ModeratedAccountAndViews) = {
|
||||
("views_available" -> mv.views.map(_.toJson)) ~
|
||||
("links" -> mv.views.map(linkJson))
|
||||
}
|
||||
|
||||
moderatedAccountAndViews.map(mv => JsonResponse("account" -> mv.account.toJson ~ bankAccountMetaData(mv)))
|
||||
}
|
||||
|
||||
case bankAlias :: "offices" :: Nil JsonGet json => {
|
||||
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
//TODO: An office model needs to be created
|
||||
val offices : List[JObject] = Nil
|
||||
JsonResponse("offices" -> offices)
|
||||
}
|
||||
|
||||
case bankAlias :: "bank" :: Nil JsonGet json => {
|
||||
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
def links = {
|
||||
def accounts = {
|
||||
("rel" -> "accounts") ~
|
||||
("href" -> {"/" + bankAlias + "/accounts"}) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> "Get list of accounts available")
|
||||
}
|
||||
|
||||
def offices = {
|
||||
("rel" -> "offices") ~
|
||||
("href" -> {"/" + bankAlias + "/offices"}) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> "Get list of offices")
|
||||
}
|
||||
|
||||
List(accounts, offices)
|
||||
}
|
||||
|
||||
val bank = for {
|
||||
bank <- Bank(bankAlias) ?~ { "bank " + bankAlias + " not found"} ~> 404
|
||||
} yield bank
|
||||
|
||||
bank.map(b => JsonResponse(b.detailedJson ~ ("links" -> links)))
|
||||
}
|
||||
|
||||
case "banks" :: Nil JsonGet json => {
|
||||
|
||||
//log the API call
|
||||
logAPICall
|
||||
|
||||
JsonResponse("banks" -> Bank.toJson(Bank.all))
|
||||
}
|
||||
})
|
||||
|
||||
// metrics API calls
|
||||
|
||||
serve("obp" / "v1.0" / "metrics" prefix {
|
||||
case "demo-bar" :: Nil JsonGet json => {
|
||||
def byURL(metric : APIMetric) : String =
|
||||
metric.url.get
|
||||
|
||||
def byUsage(x : APICallAmount, y : APICallAmount) =
|
||||
x.amount > y.amount
|
||||
|
||||
val results = APICallAmounts(APIMetric.findAll.groupBy[String](byURL).toSeq.map(t => APICallAmount(t._1,t._2.length)).toList.sort(byUsage))
|
||||
|
||||
JsonResponse(Extraction.decompose(results))
|
||||
}
|
||||
|
||||
case "demo-line" :: Nil JsonGet json => {
|
||||
|
||||
def byDay(metric : APIMetric) : Date = {
|
||||
val metricDate = metric.date.get
|
||||
val cal = Calendar.getInstance()
|
||||
cal.setTime(metricDate)
|
||||
cal.set(Calendar.HOUR,0)
|
||||
cal.set(Calendar.MINUTE,0)
|
||||
cal.set(Calendar.SECOND,0)
|
||||
cal.set(Calendar.MILLISECOND,0)
|
||||
cal.getTime
|
||||
}
|
||||
|
||||
def byOldestDate(x : APICallsForDay, y : APICallsForDay) : Boolean =
|
||||
x.date before y.date
|
||||
|
||||
val results = APICallsPerDay(APIMetric.findAll.groupBy[Date](byDay).toSeq.map(t => APICallsForDay(t._2.length,t._1)).toList.sort(byOldestDate))
|
||||
JsonResponse(Extraction.decompose(results))
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
1873
MavLift/src/main/scala/code/api/OBPAPI1.1.scala
Normal file
1873
MavLift/src/main/scala/code/api/OBPAPI1.1.scala
Normal file
File diff suppressed because it is too large
Load Diff
87
MavLift/src/main/scala/code/api/OBPRestHelper.scala
Normal file
87
MavLift/src/main/scala/code/api/OBPRestHelper.scala
Normal file
@ -0,0 +1,87 @@
|
||||
package code.api
|
||||
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.http.Req
|
||||
import net.liftweb.common._
|
||||
import net.liftweb.http.LiftResponse
|
||||
import net.liftweb.http.JsonResponse
|
||||
import code.util.APIUtil._
|
||||
import code.model.User
|
||||
import code.api.OAuthHandshake._
|
||||
|
||||
class OBPRestHelper extends RestHelper with Loggable {
|
||||
|
||||
implicit def jsonResponseBoxToJsonReponse(box: Box[JsonResponse]): JsonResponse = {
|
||||
box match {
|
||||
case Full(r) => r
|
||||
case Failure(msg, _, _) => {
|
||||
logger.info("API Failure: " + msg)
|
||||
errorJsonResponse(msg)
|
||||
}
|
||||
case _ => errorJsonResponse()
|
||||
}
|
||||
}
|
||||
|
||||
def failIfBadOauth(fn: (Box[User]) => Box[JsonResponse]) : JsonResponse = {
|
||||
if (isThereAnOAuthHeader) {
|
||||
getUser match {
|
||||
case Full(u) => fn(Full(u))
|
||||
case Failure(msg, _, _) => errorJsonResponse(msg)
|
||||
case _ => errorJsonResponse("oauth error")
|
||||
}
|
||||
} else fn(Empty)
|
||||
}
|
||||
|
||||
class RichStringList(list: List[String]) {
|
||||
val listLen = list.length
|
||||
|
||||
/**
|
||||
* Normally we would use ListServeMagic's prefix function, but it works with PartialFunction[Req, () => Box[LiftResponse]]
|
||||
* instead of the PartialFunction[Req, Box[User] => Box[JsonResponse]] that we need. This function does the same thing, really.
|
||||
*/
|
||||
def oPrefix(pf: PartialFunction[Req, Box[User] => Box[JsonResponse]]): PartialFunction[Req, Box[User] => Box[JsonResponse]] =
|
||||
new PartialFunction[Req, Box[User] => Box[JsonResponse]] {
|
||||
def isDefinedAt(req: Req): Boolean =
|
||||
req.path.partPath.startsWith(list) && {
|
||||
pf.isDefinedAt(req.withNewPath(req.path.drop(listLen)))
|
||||
}
|
||||
|
||||
def apply(req: Req): Box[User] => Box[JsonResponse] =
|
||||
pf.apply(req.withNewPath(req.path.drop(listLen)))
|
||||
}
|
||||
}
|
||||
|
||||
//Give all lists of strings in OBPRestHelpers the oPrefix method
|
||||
implicit def stringListToRichStringList(list : List[String]) : RichStringList = new RichStringList(list)
|
||||
|
||||
def oauthServe(handler : PartialFunction[Req, Box[User] => Box[JsonResponse]]) : Unit = {
|
||||
val obpHandler : PartialFunction[Req, () => Box[LiftResponse]] = {
|
||||
new PartialFunction[Req, () => Box[LiftResponse]] {
|
||||
def apply(r : Req) = {
|
||||
failIfBadOauth {
|
||||
handler(r)
|
||||
}
|
||||
}
|
||||
def isDefinedAt(r : Req) = handler.isDefinedAt(r)
|
||||
}
|
||||
}
|
||||
serve(obpHandler)
|
||||
}
|
||||
|
||||
override protected def serve(handler: PartialFunction[Req, () => Box[LiftResponse]]) : Unit= {
|
||||
|
||||
val obpHandler : PartialFunction[Req, () => Box[LiftResponse]] = {
|
||||
new PartialFunction[Req, () => Box[LiftResponse]] {
|
||||
def apply(r : Req) = {
|
||||
//Wraps the partial function with some logging
|
||||
logAPICall
|
||||
handler(r)
|
||||
}
|
||||
def isDefinedAt(r : Req) = handler.isDefinedAt(r)
|
||||
}
|
||||
}
|
||||
super.serve(obpHandler)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
172
MavLift/src/main/scala/code/api/bankmock.scala
Normal file
172
MavLift/src/main/scala/code/api/bankmock.scala
Normal file
@ -0,0 +1,172 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.api
|
||||
|
||||
import net.liftweb.common.{Box,Full,Loggable}
|
||||
import net.liftweb.mapper.By
|
||||
import net.liftweb.http.S
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.util.Props
|
||||
import net.liftweb.http.JsonResponse
|
||||
import net.liftweb.json.Extraction
|
||||
import net.liftweb.json.JsonAST.JValue
|
||||
import code.model.Token
|
||||
import code.model.TokenType
|
||||
import net.liftweb.util.Helpers.tryo
|
||||
import net.liftweb.json.Serialization
|
||||
import net.liftweb.json.NoTypeHints
|
||||
|
||||
case class ErrorMessage(
|
||||
error : String
|
||||
)
|
||||
|
||||
case class SuccessMessage(
|
||||
success : String
|
||||
)
|
||||
|
||||
case class TokenValidity(
|
||||
isValid : Boolean
|
||||
)
|
||||
|
||||
case class ApplicationInformation(
|
||||
name : String,
|
||||
callbackURL : String
|
||||
)
|
||||
|
||||
case class Verifier(
|
||||
value : String
|
||||
)
|
||||
|
||||
case class UserData(
|
||||
id : String
|
||||
)
|
||||
|
||||
/**
|
||||
* this object provides the API call required for the Bank mock,
|
||||
* They are required during the User authentication / Application Authorization steps
|
||||
* that the Bank Mock need to handle as part of the OAuth 1.0 protocol authentication.
|
||||
*/
|
||||
object BankMockAPI extends RestHelper with Loggable {
|
||||
|
||||
implicit def errorToJson(error: ErrorMessage): JValue = Extraction.decompose(error)
|
||||
implicit def successToJson(success: SuccessMessage): JValue = Extraction.decompose(success)
|
||||
implicit def TokenValidityToJson(msg: TokenValidity): JValue = Extraction.decompose(msg)
|
||||
implicit def applicationInfoToJson(info: ApplicationInformation): JValue = Extraction.decompose(info)
|
||||
implicit def verifierToJson(verifier: Verifier): JValue = Extraction.decompose(verifier)
|
||||
|
||||
//extract and compare the sent key with the local one (shared secret)
|
||||
def isValidKey : Boolean = {
|
||||
val sentKey : Box[String] =
|
||||
for{
|
||||
req <- S.request
|
||||
sentKey <- req.header("BankMockKey")
|
||||
} yield sentKey
|
||||
val localKey : Box[String] = Props.get("BankMockKey")
|
||||
localKey == sentKey
|
||||
}
|
||||
|
||||
def requestToken(token : String) : Box[Token] =
|
||||
Token.find(By(Token.key,token), By(Token.tokenType,TokenType.Request))
|
||||
|
||||
serve("obp" / "v1.0" prefix {
|
||||
case "request-token-verification" :: Nil JsonGet _ => {
|
||||
if(isValidKey)
|
||||
S.param("oauth_token") match {
|
||||
case Full(token) => {
|
||||
requestToken(token) match {
|
||||
case Full(tkn) => JsonResponse(TokenValidity(tkn.isValid), Nil, Nil, 200)
|
||||
case _ => JsonResponse(ErrorMessage("invalid or expired request token"), Nil, Nil, 401)
|
||||
}
|
||||
}
|
||||
case _ => JsonResponse(ErrorMessage("No request token"), Nil, Nil, 401)
|
||||
}
|
||||
else
|
||||
JsonResponse(ErrorMessage("No key found or wrong key"), Nil, Nil, 401)
|
||||
}
|
||||
|
||||
case "application-information" :: Nil JsonGet _ => {
|
||||
if(isValidKey)
|
||||
S.param("oauth_token") match {
|
||||
case Full(token) => {
|
||||
requestToken(token) match {
|
||||
case Full(tkn) =>
|
||||
if(tkn.isValid)
|
||||
tkn.consumerId.foreign match {
|
||||
case Full(app) => {
|
||||
val applicationInfo = ApplicationInformation(
|
||||
name = app.name,
|
||||
callbackURL = tkn.callbackURL.get
|
||||
)
|
||||
JsonResponse(applicationInfo, Nil, Nil, 200)
|
||||
}
|
||||
case _ => JsonResponse(ErrorMessage("Application not found"), Nil, Nil, 400)
|
||||
}
|
||||
else
|
||||
JsonResponse(ErrorMessage("Expired request token"), Nil, Nil, 401)
|
||||
case _ => JsonResponse(ErrorMessage("Request token not found"), Nil, Nil, 401)
|
||||
}
|
||||
}
|
||||
case _ => JsonResponse(ErrorMessage("No request token"), Nil, Nil, 401)
|
||||
}
|
||||
else
|
||||
JsonResponse(ErrorMessage("No key found or wrong key"), Nil, Nil, 401)
|
||||
}
|
||||
case "verifiers" :: Nil JsonPost json -> _ => {
|
||||
if(isValidKey)
|
||||
S.param("oauth_token") match {
|
||||
case Full(token) => {
|
||||
tryo{
|
||||
json.extract[UserData]
|
||||
} match {
|
||||
case Full(userData) => {
|
||||
requestToken(token) match {
|
||||
case Full(tkn) =>{
|
||||
//associate the token with the user
|
||||
tkn.userId(userData.id)
|
||||
val verifier = tkn.gernerateVerifier
|
||||
tkn.save
|
||||
JsonResponse(Verifier(verifier), Nil, Nil, 200)
|
||||
}
|
||||
case _ => JsonResponse(ErrorMessage("Request token not found"), Nil, Nil, 401)
|
||||
}
|
||||
}
|
||||
case _ => JsonResponse(ErrorMessage("Wrong JSON format"), Nil, Nil, 401)
|
||||
}
|
||||
}
|
||||
case _ => JsonResponse(ErrorMessage("No OAuth token"), Nil, Nil, 401)
|
||||
}
|
||||
else
|
||||
JsonResponse(ErrorMessage("No key found or wrong key"), Nil, Nil, 401)
|
||||
}
|
||||
})
|
||||
}
|
||||
186
MavLift/src/main/scala/code/api/cash.scala
Normal file
186
MavLift/src/main/scala/code/api/cash.scala
Normal file
@ -0,0 +1,186 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.api
|
||||
|
||||
import net.liftweb.http._
|
||||
import net.liftweb.http.rest._
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.Printer._
|
||||
import net.liftweb.json.Extraction._
|
||||
import net.liftweb.json.JsonAST
|
||||
import JsonAST._
|
||||
import net.liftweb.common.{Failure,Full, Empty, Box,Loggable}
|
||||
import net.liftweb.mongodb._
|
||||
import com.mongodb.casbah.Imports._
|
||||
import _root_.java.math.MathContext
|
||||
import org.bson.types._
|
||||
import org.joda.time.{ DateTime, DateTimeZone }
|
||||
import java.util.regex.Pattern
|
||||
import _root_.net.liftweb.util._
|
||||
import _root_.net.liftweb.http._
|
||||
import _root_.net.liftweb.mapper._
|
||||
import _root_.net.liftweb.util.Helpers._
|
||||
import _root_.net.liftweb.sitemap._
|
||||
import _root_.scala.xml._
|
||||
import _root_.net.liftweb.http.S._
|
||||
import _root_.net.liftweb.http.RequestVar
|
||||
import _root_.net.liftweb.common.Full
|
||||
import net.liftweb.mongodb.{ Skip, Limit }
|
||||
import _root_.net.liftweb.http.S._
|
||||
import _root_.net.liftweb.mapper.view._
|
||||
import com.mongodb._
|
||||
import code.model.dataAccess._
|
||||
import java.util.Date
|
||||
import net.liftweb.util.Helpers.now
|
||||
import net.liftweb.json.Extraction
|
||||
import _root_.net.liftweb.json.Serialization
|
||||
import net.liftweb.json.NoTypeHints
|
||||
import scala.math.BigDecimal._
|
||||
|
||||
case class CashTransaction(
|
||||
otherParty : String,
|
||||
date : Date,
|
||||
amount : Double,
|
||||
kind : String,
|
||||
label : String,
|
||||
otherInformation : String
|
||||
)
|
||||
|
||||
object CashAccountAPI extends RestHelper with Loggable {
|
||||
|
||||
implicit def errorToJson(error: ErrorMessage): JValue = Extraction.decompose(error)
|
||||
implicit def successToJson(msg: SuccessMessage): JValue = Extraction.decompose(msg)
|
||||
|
||||
def isValidKey : Boolean = {
|
||||
val sentKey : Box[String] =
|
||||
for{
|
||||
req <- S.request
|
||||
sentKey <- req.header("cashApplicationKey")
|
||||
} yield sentKey
|
||||
val localKey : Box[String] = Props.get("cashApplicationKey")
|
||||
localKey == sentKey
|
||||
}
|
||||
|
||||
serve("obp" / "v1.0" prefix {
|
||||
|
||||
case "cash-accounts" :: id :: "transactions" :: Nil JsonPost json -> _ => {
|
||||
if(isValidKey)
|
||||
Account.find(id) match {
|
||||
case Full(account) =>
|
||||
tryo{
|
||||
json.extract[CashTransaction]
|
||||
} match {
|
||||
case Full(cashTransaction) => {
|
||||
|
||||
val thisAccountBank = OBPBank.createRecord.
|
||||
IBAN("").
|
||||
national_identifier("").
|
||||
name(account.bankName)
|
||||
|
||||
val thisAccount = OBPAccount.createRecord.
|
||||
holder(account.holder.get).
|
||||
number(account.number.get).
|
||||
kind(account.kind.get).
|
||||
bank(thisAccountBank)
|
||||
|
||||
val otherAccountBank = OBPBank.createRecord.
|
||||
IBAN("").
|
||||
national_identifier("").
|
||||
name("")
|
||||
|
||||
val otherAccount = OBPAccount.createRecord.
|
||||
holder(cashTransaction.otherParty).
|
||||
number("").
|
||||
kind("").
|
||||
bank(otherAccountBank)
|
||||
|
||||
val amount : BigDecimal = {
|
||||
if(cashTransaction.kind == "in")
|
||||
BigDecimal(cashTransaction.amount).setScale(2,RoundingMode.HALF_UP).abs
|
||||
else
|
||||
BigDecimal((cashTransaction.amount * (-1) )).setScale(2,RoundingMode.HALF_UP)
|
||||
}
|
||||
|
||||
val newBalance : OBPBalance = OBPBalance.createRecord.
|
||||
currency(account.currency.get).
|
||||
amount(account.balance.get + amount)
|
||||
|
||||
val newValue : OBPValue = OBPValue.createRecord.
|
||||
currency(account.currency.get).
|
||||
amount(amount)
|
||||
|
||||
val details = OBPDetails.createRecord.
|
||||
type_en("cash").
|
||||
type_de("Bargeld").
|
||||
posted(cashTransaction.date).
|
||||
other_data(cashTransaction.otherInformation).
|
||||
new_balance(newBalance).
|
||||
value(newValue).
|
||||
completed(cashTransaction.date).
|
||||
label(cashTransaction.label)
|
||||
|
||||
val transaction = OBPTransaction.createRecord.
|
||||
this_account(thisAccount).
|
||||
other_account(otherAccount).
|
||||
details(details)
|
||||
|
||||
val env = OBPEnvelope.createRecord.
|
||||
obp_transaction(transaction).save
|
||||
account.balance(account.balance.get + amount).lastUpdate(now)
|
||||
env.createAliases
|
||||
env.save
|
||||
|
||||
JsonResponse(SuccessMessage("transaction successfully added"), Nil, Nil, 200)
|
||||
}
|
||||
case _ =>{
|
||||
val error = "Post data must be in the format: \n" +
|
||||
pretty(
|
||||
JsonAST.render(
|
||||
Extraction.decompose(
|
||||
CashTransaction(
|
||||
otherParty = "other party",
|
||||
date = new Date,
|
||||
amount = 1231.12,
|
||||
kind = "in / out",
|
||||
label = "what is this transaction for",
|
||||
otherInformation = "more info"
|
||||
))))
|
||||
JsonResponse(ErrorMessage(error), Nil, Nil, 400)
|
||||
}
|
||||
}
|
||||
case _ => JsonResponse(ErrorMessage("Account " + id + " not found" ), Nil, Nil, 400)
|
||||
}
|
||||
else
|
||||
JsonResponse(ErrorMessage("No key found or wrong key"), Nil, Nil, 401)
|
||||
}
|
||||
})
|
||||
}
|
||||
263
MavLift/src/main/scala/code/api/importer.scala
Normal file
263
MavLift/src/main/scala/code/api/importer.scala
Normal file
@ -0,0 +1,263 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.api
|
||||
|
||||
import code.actors.EnvelopeInserter
|
||||
import net.liftweb.http._
|
||||
import net.liftweb.http.rest._
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.Printer._
|
||||
import net.liftweb.json.Extraction._
|
||||
import net.liftweb.json.JsonAST._
|
||||
import java.util.Calendar
|
||||
import net.liftweb.common.Failure
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.common.Empty
|
||||
import net.liftweb.mongodb._
|
||||
import net.liftweb.json.JsonAST.JString
|
||||
import com.mongodb.casbah.Imports._
|
||||
import _root_.java.math.MathContext
|
||||
import org.bson.types._
|
||||
import org.joda.time.{ DateTime, DateTimeZone }
|
||||
import java.util.regex.Pattern
|
||||
import _root_.net.liftweb.common._
|
||||
import _root_.net.liftweb.util._
|
||||
import _root_.net.liftweb.http._
|
||||
import _root_.net.liftweb.mapper._
|
||||
import _root_.net.liftweb.util.Helpers._
|
||||
import _root_.net.liftweb.sitemap._
|
||||
import _root_.scala.xml._
|
||||
import _root_.net.liftweb.http.S._
|
||||
import _root_.net.liftweb.http.RequestVar
|
||||
import _root_.net.liftweb.util.Helpers._
|
||||
import _root_.net.liftweb.common.Full
|
||||
import net.liftweb.mongodb.{ Skip, Limit }
|
||||
import _root_.net.liftweb.http.S._
|
||||
import _root_.net.liftweb.mapper.view._
|
||||
import com.mongodb._
|
||||
import code.model.dataAccess.{ Account, OBPEnvelope, OBPUser, HostedAccount, LocalStorage }
|
||||
import code.model.{ModeratedTransaction, ModeratedBankAccount, View, BankAccount, Public, Bank, User}
|
||||
import code.model.dataAccess.OBPEnvelope._
|
||||
import java.util.Date
|
||||
import code.api.OAuthHandshake._
|
||||
|
||||
object ImporterAPI extends RestHelper with Loggable {
|
||||
serve {
|
||||
//a temporary way to add transaction via api for a single specific exception case. should be removed later.
|
||||
case "api" :: "tmp" :: "transactions" :: Nil JsonPost json => {
|
||||
val secretKey = S.param("secret")
|
||||
|
||||
def addMatchingTransactions(secret: String) = {
|
||||
val rawEnvelopes = json._1.children
|
||||
val envelopes = rawEnvelopes.flatMap(OBPEnvelope.fromJValue)
|
||||
val matchingEnvelopes = for {
|
||||
e <- envelopes
|
||||
bankName <- Props.get("exceptional_account_bankName")
|
||||
number <- Props.get("exceptional_account_number")
|
||||
kind <- Props.get("exceptional_account_kind")
|
||||
if(e.obp_transaction.get.this_account.get.bank.get.name.get == bankName)
|
||||
if(e.obp_transaction.get.this_account.get.number.get == number)
|
||||
if(e.obp_transaction.get.this_account.get.kind.get == kind)
|
||||
} yield e
|
||||
|
||||
val ipAddress = json._2.remoteAddr
|
||||
logger.info("Received " + rawEnvelopes.size +
|
||||
" json transactions to insert from ip address " + ipAddress)
|
||||
logger.info("Received " + matchingEnvelopes.size +
|
||||
" valid transactions to insert from ip address " + ipAddress)
|
||||
|
||||
/**
|
||||
* Using an actor to do insertions avoids concurrency issues with
|
||||
* duplicate transactions by processing transaction batches one
|
||||
* at a time. We'll have to monitor this to see if non-concurrent I/O
|
||||
* is too inefficient. If it is, we could break it up into one actor
|
||||
* per "Account".
|
||||
*/
|
||||
val createdEnvelopes = EnvelopeInserter !? (3 seconds, matchingEnvelopes)
|
||||
|
||||
createdEnvelopes match {
|
||||
case Full(l: List[JObject]) =>{
|
||||
if(matchingEnvelopes.size!=0)
|
||||
{
|
||||
Account.find(("number" -> Props.get("exceptional_account_number").getOrElse("")) ~
|
||||
("bankName" -> Props.get("exceptional_account_bankName").getOrElse("")) ~
|
||||
("kind" -> Props.get("exceptional_account_kind").getOrElse("")))
|
||||
match {
|
||||
case Full(account) => account.lastUpdate(new Date).save
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
JsonResponse(JArray(l))
|
||||
}
|
||||
case _ => InternalServerErrorResponse()
|
||||
}
|
||||
}
|
||||
|
||||
def valid(secret : String) = {
|
||||
val authorised = for (validSecret <- Props.get("exceptional_account_secret"))
|
||||
yield secret == validSecret
|
||||
|
||||
authorised getOrElse false
|
||||
}
|
||||
|
||||
secretKey match {
|
||||
case Full(s) => if(valid(s))
|
||||
addMatchingTransactions(s)
|
||||
else
|
||||
UnauthorizedResponse("wrong secret key")
|
||||
case _ => NotFoundResponse()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
serve {
|
||||
|
||||
/**
|
||||
* curl -i -H "Content-Type: application/json" -X POST -d '{
|
||||
* "obp_transaction":{
|
||||
* "this_account":{
|
||||
* "holder":"Music Pictures Limited",
|
||||
* "number":"123567",
|
||||
* "kind":"current",
|
||||
* "bank":{
|
||||
* "IBAN":"DE1235123612",
|
||||
* "national_identifier":"de.10010010",
|
||||
* "name":"Postbank"
|
||||
* }
|
||||
* },
|
||||
* "other_account":{
|
||||
* "holder":"Client 1",
|
||||
* "number":"123567",
|
||||
* "kind":"current",
|
||||
* "bank":{
|
||||
* "IBAN":"UK12222879",
|
||||
* "national_identifier":"uk.10010010",
|
||||
* "name":"HSBC"
|
||||
* }
|
||||
* },
|
||||
* "details":{
|
||||
* "type_en":"Transfer",
|
||||
* "type_de":"Überweisung",
|
||||
* "posted":{
|
||||
* "$dt":"2012-01-04T18:06:22.000Z"
|
||||
* },
|
||||
* "completed":{
|
||||
* "$dt":"2012-09-04T18:52:13.000Z"
|
||||
* },
|
||||
* "new_balance":{
|
||||
* "currency":"EUR",
|
||||
* "amount":"4323.45"
|
||||
* },
|
||||
* "value":{
|
||||
* "currency":"EUR",
|
||||
* "amount":"123.45"
|
||||
* },
|
||||
* "other_data":"9"
|
||||
* }
|
||||
* }
|
||||
* } ' http://localhost:8080/api/transactions
|
||||
*/
|
||||
case "api" :: "transactions" :: Nil JsonPost json => {
|
||||
|
||||
//
|
||||
// WARNING!
|
||||
//
|
||||
// If you have not configured a web server to restrict this URL
|
||||
// appropriately, anyone will be
|
||||
// able to post transactions to your database. This would obviously
|
||||
// be undesirable. So you should
|
||||
// definitely sort that out.
|
||||
//
|
||||
//
|
||||
|
||||
val rawEnvelopes = json._1.children
|
||||
|
||||
val envelopes : List[OBPEnvelope]= rawEnvelopes.flatMap(e => {
|
||||
OBPEnvelope.envlopesFromJvalue(e)
|
||||
})
|
||||
|
||||
val ipAddress = json._2.remoteAddr
|
||||
logger.info("Received " + rawEnvelopes.size +
|
||||
" json transactions to insert from ip address " + ipAddress)
|
||||
logger.info("Received " + envelopes.size +
|
||||
" valid transactions to insert from ip address " + ipAddress)
|
||||
|
||||
/**
|
||||
* Using an actor to do insertions avoids concurrency issues with
|
||||
* duplicate transactions by processing transaction batches one
|
||||
* at a time. We'll have to monitor this to see if non-concurrent I/O
|
||||
* is too inefficient. If it is, we could break it up into one actor
|
||||
* per "Account".
|
||||
*/
|
||||
val createdEnvelopes = EnvelopeInserter !? (3 seconds, envelopes)
|
||||
|
||||
createdEnvelopes match {
|
||||
case Full(l: List[JObject]) =>{
|
||||
logger.info("inserted " + l.size + "transactions")
|
||||
if(envelopes.size!=0)
|
||||
{
|
||||
//we assume here that all the Envelopes concerns only one account
|
||||
val accountNumber = envelopes(0).obp_transaction.get.this_account.get.number.get
|
||||
val bankName = envelopes(0).obp_transaction.get.this_account.get.bank.get.name.get
|
||||
val accountKind = envelopes(0).obp_transaction.get.this_account.get.kind.get
|
||||
val holder = envelopes(0).obp_transaction.get.this_account.get.holder.get
|
||||
//Get all accounts with this account number and kind
|
||||
val accounts = Account.findAll(("number" -> accountNumber) ~ ("kind" -> accountKind) ~ ("holder" -> holder))
|
||||
//Now get the one that actually belongs to the right bank
|
||||
val wantedAccount = accounts.find(_.bankName == bankName)
|
||||
wantedAccount match {
|
||||
case Some(account) => {
|
||||
def updateAccountBalance() = {
|
||||
val newest = OBPEnvelope.findAll(("obp_transaction.this_account.number" -> accountNumber) ~
|
||||
("obp_transaction.this_account.kind" -> accountKind) ~
|
||||
("obp_transaction.this_account.bank.name" -> bankName),
|
||||
("obp_transaction.details.completed" -> -1), Limit(1)).headOption
|
||||
if(newest.isDefined) {
|
||||
logger.debug("Updating current balance for " + bankName + "/" + accountNumber + "/" + accountKind)
|
||||
account.balance(newest.get.obp_transaction.get.details.get.new_balance.get.amount.get).save
|
||||
}
|
||||
else logger.warn("Could not update latest account balance")
|
||||
}
|
||||
account.lastUpdate(new Date).save
|
||||
updateAccountBalance()
|
||||
}
|
||||
case _ => logger.info("BankName/accountNumber/kind not found : " + bankName + "/" + accountNumber + "/" + accountKind)
|
||||
}
|
||||
}
|
||||
JsonResponse(JArray(l))
|
||||
}
|
||||
case _ => InternalServerErrorResponse()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
502
MavLift/src/main/scala/code/api/oauth1.0.scala
Normal file
502
MavLift/src/main/scala/code/api/oauth1.0.scala
Normal file
@ -0,0 +1,502 @@
|
||||
/**
|
||||
Open Bank Project
|
||||
|
||||
Copyright 2011,2012 TESOBE / Music Pictures Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Open Bank Project (http://www.openbankproject.com)
|
||||
Copyright 2011,2012 TESOBE / Music Pictures Ltd
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Everett Sochowski: everett AT tesobe DOT com
|
||||
Ayoub Benali : ayoub AT tesobe Dot com
|
||||
*/
|
||||
package code.api
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.http.Req
|
||||
import net.liftweb.http.GetRequest
|
||||
import net.liftweb.http.PostRequest
|
||||
import net.liftweb.http.LiftResponse
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.http.InMemoryResponse
|
||||
import net.liftweb.common.{Full,Empty,Loggable}
|
||||
import net.liftweb.http.S
|
||||
import code.model.{Nonce, Consumer, Token}
|
||||
import net.liftweb.mapper.By
|
||||
import java.util.Date
|
||||
import java.net.{URLEncoder, URLDecoder}
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import javax.crypto.Mac
|
||||
import net.liftweb.util.Helpers
|
||||
import code.model.AppType._
|
||||
import code.model.TokenType._
|
||||
import scala.compat.Platform
|
||||
import scala.xml.NodeSeq
|
||||
import Helpers._
|
||||
import net.liftweb.util.Props
|
||||
import code.model.TokenType
|
||||
import code.model.User
|
||||
import net.liftweb.common.Failure
|
||||
|
||||
/**
|
||||
* This object provides the API calls necessary to third party applications
|
||||
* so they could authenticate their users.
|
||||
*/
|
||||
|
||||
object OAuthHandshake extends RestHelper with Loggable {
|
||||
serve
|
||||
{
|
||||
//Handling get request for a "request token"
|
||||
case Req("oauth" :: "initiate" :: Nil,_ ,PostRequest) =>
|
||||
{
|
||||
//Extract the OAuth parameters from the header and test if the request is valid
|
||||
var (httpCode, message, oAuthParameters) = validator("requestToken", "POST")
|
||||
//Test if the request is valid
|
||||
if(httpCode==200)
|
||||
{
|
||||
//Generate the token and secret
|
||||
val (token,secret) = generateTokenAndSecret()
|
||||
//Save the token that we have generated
|
||||
if(saveRequestToken(oAuthParameters,token, secret))
|
||||
message="oauth_token="+token+"&oauth_token_secret="+
|
||||
secret+"&oauth_callback_confirmed=true"
|
||||
}
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
//return an HTTP response
|
||||
Full(InMemoryResponse(message.getBytes,headers,Nil,httpCode))
|
||||
}
|
||||
|
||||
case Req("oauth" :: "token" :: Nil,_, PostRequest) =>
|
||||
{
|
||||
//Extract the OAuth parameters from the header and test if the request is valid
|
||||
var (httpCode, message, oAuthParameters) = validator("authorizationToken", "POST")
|
||||
//Test if the request is valid
|
||||
if(httpCode==200)
|
||||
{
|
||||
//Generate the token and secret
|
||||
val (token,secret) = generateTokenAndSecret()
|
||||
//Save the token that we have generated
|
||||
if(saveAuthorizationToken(oAuthParameters,token, secret))
|
||||
//remove the request token so the application could not exchange it
|
||||
//again to get an other access token
|
||||
Token.find(By(Token.key,oAuthParameters.get("oauth_token").get)) match {
|
||||
case Full(requestToken) => requestToken.delete_!
|
||||
case _ => None
|
||||
}
|
||||
|
||||
message="oauth_token="+token+"&oauth_token_secret="+secret
|
||||
}
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
//return an HTTP response
|
||||
Full(InMemoryResponse(message.getBytes,headers,Nil,httpCode))
|
||||
}
|
||||
}
|
||||
|
||||
//Check if the request (access toke or request token) is valid and return a tuple
|
||||
def validator(requestType : String, httpMethod : String) : (Int, String, Map[String,String]) = {
|
||||
//return a Map containing the OAuth parameters : oauth_prameter -> value
|
||||
def getAllParameters : Map[String,String]= {
|
||||
|
||||
//Convert the string containing the list of OAuth parameters to a Map
|
||||
def toMap(parametersList : String) = {
|
||||
//transform the string "oauth_prameter="value""
|
||||
//to a tuple (oauth_parameter,Decoded(value))
|
||||
def dynamicListExtract(input: String) = {
|
||||
val oauthPossibleParameters =
|
||||
List(
|
||||
"oauth_consumer_key",
|
||||
"oauth_nonce",
|
||||
"oauth_signature_method",
|
||||
"oauth_timestamp",
|
||||
"oauth_version",
|
||||
"oauth_signature",
|
||||
"oauth_callback",
|
||||
"oauth_token",
|
||||
"oauth_verifier"
|
||||
)
|
||||
|
||||
if (input contains "=") {
|
||||
val split = input.split("=",2)
|
||||
val parameterValue = split(1).replace("\"","")
|
||||
//add only OAuth parameters and not empty
|
||||
if(oauthPossibleParameters.contains(split(0)) && ! parameterValue.isEmpty)
|
||||
Some(split(0),parameterValue) // return key , value
|
||||
else
|
||||
None
|
||||
}
|
||||
else
|
||||
None
|
||||
}
|
||||
//we delete the "Oauth" prefix and all the white spaces that may exist in the string
|
||||
val cleanedParameterList = parametersList.stripPrefix("OAuth").replaceAll("\\s","")
|
||||
Map(cleanedParameterList.split(",").flatMap(dynamicListExtract _): _*)
|
||||
}
|
||||
|
||||
S.request match {
|
||||
case Full(a) => a.header("Authorization") match {
|
||||
case Full(parameters) => toMap(parameters)
|
||||
case _ => Map(("",""))
|
||||
}
|
||||
case _ => Map(("",""))
|
||||
}
|
||||
}
|
||||
//return true if the authorization header has a duplicated parameter
|
||||
def duplicatedParameters = {
|
||||
var output=false
|
||||
val authorizationParameters = S.request.get.header("Authorization").get.split(",")
|
||||
|
||||
//count the iterations of a parameter in the authorization header
|
||||
def countPram(parameterName : String, parametersArray :Array[String] )={
|
||||
var i = 0
|
||||
parametersArray.foreach(t => {if (t.split("=")(0) == parameterName) i+=1})
|
||||
i
|
||||
}
|
||||
|
||||
//return true if on of the Authorization header parameter is present more than one time
|
||||
authorizationParameters.foreach(
|
||||
t => {
|
||||
if(countPram(t.split("=")(0),authorizationParameters)>1 && !output)
|
||||
output=true
|
||||
}
|
||||
)
|
||||
output
|
||||
}
|
||||
|
||||
def suportedOAuthVersion(OAuthVersion : Option[String]) : Boolean = {
|
||||
//auth_version is OPTIONAL. If present, MUST be set to "1.0".
|
||||
OAuthVersion match
|
||||
{
|
||||
case Some(a) => a=="1" || a=="1.0"
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
def wrongTimestamp(requestTimestamp : Date) : Boolean= {
|
||||
val currentTime = Platform.currentTime / 1000
|
||||
|
||||
val timeRange : Long = Helpers.minutes(3)
|
||||
//check if the timestamp is positive and in the time range
|
||||
requestTimestamp.getTime < 0 || requestTimestamp.before(new Date(currentTime - timeRange)) || requestTimestamp.after(new Date(currentTime + timeRange))
|
||||
}
|
||||
|
||||
def alReadyUsedNonce(parameters : Map[String, String]) : Boolean = {
|
||||
|
||||
/*
|
||||
* The nonce value MUST be unique across all requests with the
|
||||
* same timestamp, client credentials, and token combinations.
|
||||
*/
|
||||
val token = parameters.get("oauth_token") getOrElse ""
|
||||
|
||||
Nonce.count(
|
||||
By(Nonce.value,parameters.get("oauth_nonce").get),
|
||||
By(Nonce.tokenKey, token),
|
||||
By(Nonce.consumerkey,parameters.get("oauth_consumer_key").get),
|
||||
By(Nonce.timestamp, new Date(parameters.get("oauth_timestamp").get.toLong))
|
||||
) !=0
|
||||
}
|
||||
|
||||
def registeredApplication(consumerKey : String ) : Boolean = {
|
||||
Consumer.find(By(Consumer.key,consumerKey)) match {
|
||||
case Full(application) => application.isActive
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
def correctSignature(OAuthparameters : Map[String, String], httpMethod : String) = {
|
||||
//Normalize an encode the request parameters as explained in Section 3.4.1.3.2
|
||||
//of OAuth 1.0 specification (http://tools.ietf.org/html/rfc5849)
|
||||
def generateOAuthParametersString(OAuthparameters : Map[String, String]) : String = {
|
||||
def sortParam( keyAndValue1 : (String, String), keyAndValue2 : (String, String))= keyAndValue1._1.compareTo(keyAndValue2._1) < 0
|
||||
var parameters =""
|
||||
|
||||
//sort the parameters by name
|
||||
OAuthparameters.toList.sortWith(sortParam _).foreach(
|
||||
t =>
|
||||
if(t._1 != "oauth_signature")
|
||||
parameters += URLEncoder.encode(t._1,"UTF-8")+"%3D"+ URLEncoder.encode(t._2,"UTF-8")+"%26"
|
||||
|
||||
)
|
||||
parameters = parameters.dropRight(3) //remove the "&" encoded sign
|
||||
parameters
|
||||
}
|
||||
|
||||
|
||||
//prepare the base string
|
||||
var baseString = httpMethod+"&"+URLEncoder.encode(Props.get("hostname").openOr(S.hostAndPath) + S.uri,"UTF-8")+"&"
|
||||
baseString+= generateOAuthParametersString(OAuthparameters)
|
||||
|
||||
val encodeBaseString = URLEncoder.encode(baseString,"UTF-8")
|
||||
//get the key to sign
|
||||
val comsumer = Consumer.find(
|
||||
By(Consumer.key,OAuthparameters.get("oauth_consumer_key").get)
|
||||
).get
|
||||
var secret= comsumer.secret.toString
|
||||
|
||||
OAuthparameters.get("oauth_token") match {
|
||||
case Some(tokenKey) => Token.find(By(Token.key,tokenKey)) match {
|
||||
case Full(token) => secret+= "&" +token.secret.toString()
|
||||
case _ => secret+= "&"
|
||||
}
|
||||
case _ => secret+= "&"
|
||||
}
|
||||
logger.info("base string : " + baseString)
|
||||
//signing process
|
||||
val signingAlgorithm : String = if(OAuthparameters.get("oauth_signature_method").get.toLowerCase == "hmac-sha256")
|
||||
"HmacSHA256"
|
||||
else
|
||||
"HmacSHA1"
|
||||
|
||||
logger.info("signing method:" + signingAlgorithm)
|
||||
logger.info("signing key: " + secret)
|
||||
logger.info("signing key in bytes: " + secret.getBytes("UTF-8"))
|
||||
|
||||
var m = Mac.getInstance(signingAlgorithm);
|
||||
m.init(new SecretKeySpec(secret.getBytes("UTF-8"),signingAlgorithm))
|
||||
val calculatedSignature = Helpers.base64Encode(m.doFinal(baseString.getBytes))
|
||||
|
||||
logger.info("calculatedSignature:" + calculatedSignature)
|
||||
logger.info("received signature:" + OAuthparameters.get("oauth_signature").get)
|
||||
logger.info("received signature after decoding:" + URLDecoder.decode(OAuthparameters.get("oauth_signature").get))
|
||||
|
||||
calculatedSignature== URLDecoder.decode(OAuthparameters.get("oauth_signature").get,"UTF-8")
|
||||
}
|
||||
|
||||
//check if the token exists and is still valid
|
||||
def validToken(tokenKey : String, verifier : String) ={
|
||||
Token.find(By(Token.key, tokenKey),By(Token.tokenType,TokenType.Request)) match {
|
||||
case Full(token) =>
|
||||
token.isValid && token.verifier == verifier
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def validToken2(tokenKey : String) = {
|
||||
Token.find(By(Token.key, tokenKey),By(Token.tokenType,TokenType.Access)) match {
|
||||
case Full(token) => token.isValid
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
//@return the missing parameters depending of the request type
|
||||
def missingOauthParameters(parameters : Map[String, String], requestType : String) : Set[String] = {
|
||||
val parametersBase =
|
||||
List(
|
||||
"oauth_consumer_key",
|
||||
"oauth_nonce",
|
||||
"oauth_signature_method",
|
||||
"oauth_timestamp",
|
||||
"oauth_signature"
|
||||
)
|
||||
if(requestType == "requestToken")
|
||||
("oauth_callback" :: parametersBase).toSet diff parameters.keySet
|
||||
else if(requestType=="authorizationToken")
|
||||
("oauth_token" :: "oauth_verifier" :: parametersBase).toSet diff parameters.keySet
|
||||
else if(requestType=="protectedResource")
|
||||
("oauth_token" :: parametersBase).toSet diff parameters.keySet
|
||||
else
|
||||
parameters.keySet
|
||||
}
|
||||
|
||||
def supportedSignatureMethod(oauthSignatureMethod : String ) : Boolean =
|
||||
{
|
||||
oauthSignatureMethod.toLowerCase == "hmac-sha256" ||
|
||||
oauthSignatureMethod.toLowerCase == "hmac-sha1"
|
||||
}
|
||||
|
||||
var message =""
|
||||
var httpCode : Int = 500
|
||||
|
||||
var parameters = getAllParameters
|
||||
|
||||
//does all the OAuth parameters are presents?
|
||||
val missingParams = missingOauthParameters(parameters,requestType)
|
||||
if( missingParams.size != 0 )
|
||||
{
|
||||
message = "the following parameters are missing : " + missingParams.mkString(", ")
|
||||
httpCode = 400
|
||||
}
|
||||
//no parameter exists more than one times
|
||||
else if (duplicatedParameters)
|
||||
{
|
||||
message = "Duplicated oauth protocol parameters"
|
||||
httpCode = 400
|
||||
}
|
||||
//valid OAuth
|
||||
else if(!suportedOAuthVersion(parameters.get("oauth_version")))
|
||||
{
|
||||
message = "OAuth version not supported"
|
||||
httpCode = 400
|
||||
}
|
||||
//supported signature method
|
||||
else if (! supportedSignatureMethod(parameters.get("oauth_signature_method").get))
|
||||
{
|
||||
message = "Unsupported signature method, please use hmac-sha128 or hmac-sha256"
|
||||
httpCode = 400
|
||||
}
|
||||
//check if the application is registered and active
|
||||
else if(! registeredApplication(parameters.get("oauth_consumer_key").get))
|
||||
{
|
||||
logger.error("application: " + parameters.get("oauth_consumer_key").get + " not found")
|
||||
message = "Invalid consumer credentials"
|
||||
httpCode = 401
|
||||
}
|
||||
//valid timestamp
|
||||
else if(wrongTimestamp(new Date(parameters.get("oauth_timestamp").get.toLong)))
|
||||
{
|
||||
message = "wrong timestamps"
|
||||
httpCode = 400
|
||||
}
|
||||
//unused nonce
|
||||
else if (alReadyUsedNonce(parameters))
|
||||
{
|
||||
message = "Nonce already used"
|
||||
httpCode = 401
|
||||
}
|
||||
//In the case OAuth authorization token request, check if the token is still valid and the verifier is correct
|
||||
else if(requestType=="authorizationToken" && !validToken(parameters.get("oauth_token").get, parameters.get("oauth_verifier").get))
|
||||
{
|
||||
message = "Invalid or expired request token: " + parameters.get("oauth_token").get
|
||||
httpCode = 401
|
||||
}
|
||||
//In the case protected resource access request, check if the token is still valid
|
||||
else if (
|
||||
requestType=="protectedResource" &&
|
||||
! validToken2(parameters.get("oauth_token").get)
|
||||
)
|
||||
{
|
||||
message = "Invalid or expired access token: " + parameters.get("oauth_token").get
|
||||
httpCode = 401
|
||||
}
|
||||
//checking if the signature is correct
|
||||
else if(! correctSignature(parameters, httpMethod))
|
||||
{
|
||||
message = "Invalid signature"
|
||||
httpCode = 401
|
||||
}
|
||||
else
|
||||
httpCode = 200
|
||||
logger.error("error message : " + message)
|
||||
|
||||
(httpCode, message, parameters)
|
||||
}
|
||||
private def generateTokenAndSecret() =
|
||||
{
|
||||
// generate some random strings
|
||||
val token_message = Helpers.randomString(40)
|
||||
val secret_message = Helpers.randomString(40)
|
||||
|
||||
(token_message, secret_message)
|
||||
}
|
||||
private def saveRequestToken(oAuthParameters : Map[String, String], tokenKey : String, tokenSecret : String) =
|
||||
{
|
||||
import code.model.{Nonce, Token, TokenType}
|
||||
|
||||
val nonce = Nonce.create
|
||||
nonce.consumerkey(oAuthParameters.get("oauth_consumer_key").get)
|
||||
nonce.timestamp(new Date(oAuthParameters.get("oauth_timestamp").get.toLong))
|
||||
nonce.value(oAuthParameters.get("oauth_nonce").get)
|
||||
val nonceSaved = nonce.save()
|
||||
|
||||
val token = Token.create
|
||||
token.tokenType(TokenType.Request)
|
||||
Consumer.find(By(Consumer.key,oAuthParameters.get("oauth_consumer_key").get)) match {
|
||||
case Full(consumer) => token.consumerId(consumer.id)
|
||||
case _ => None
|
||||
}
|
||||
token.key(tokenKey)
|
||||
token.secret(tokenSecret)
|
||||
if(! oAuthParameters.get("oauth_callback").get.isEmpty)
|
||||
token.callbackURL(URLDecoder.decode(oAuthParameters.get("oauth_callback").get,"UTF-8"))
|
||||
else
|
||||
token.callbackURL("oob")
|
||||
val currentTime = Platform.currentTime
|
||||
val tokenDuration : Long = Helpers.minutes(30)
|
||||
token.duration(tokenDuration)
|
||||
token.expirationDate(new Date(currentTime+tokenDuration))
|
||||
token.insertDate(new Date(currentTime))
|
||||
val tokenSaved = token.save()
|
||||
|
||||
nonceSaved && tokenSaved
|
||||
}
|
||||
private def saveAuthorizationToken(oAuthParameters : Map[String, String], tokenKey : String, tokenSecret : String) =
|
||||
{
|
||||
import code.model.{Nonce, Token, TokenType}
|
||||
|
||||
val nonce = Nonce.create
|
||||
nonce.consumerkey(oAuthParameters.get("oauth_consumer_key").get)
|
||||
nonce.timestamp(new Date(oAuthParameters.get("oauth_timestamp").get.toLong))
|
||||
nonce.tokenKey(oAuthParameters.get("oauth_token").get)
|
||||
nonce.value(oAuthParameters.get("oauth_nonce").get)
|
||||
val nonceSaved = nonce.save()
|
||||
|
||||
val token = Token.create
|
||||
token.tokenType(TokenType.Access)
|
||||
Consumer.find(By(Consumer.key,oAuthParameters.get("oauth_consumer_key").get)) match {
|
||||
case Full(consumer) => token.consumerId(consumer.id)
|
||||
case _ => None
|
||||
}
|
||||
Token.find(By(Token.key, oAuthParameters.get("oauth_token").get)) match {
|
||||
case Full(requestToken) => token.userId(requestToken.userId)
|
||||
case _ => None
|
||||
}
|
||||
token.key(tokenKey)
|
||||
token.secret(tokenSecret)
|
||||
val currentTime = Platform.currentTime
|
||||
val tokenDuration : Long = Helpers.weeks(4)
|
||||
token.duration(tokenDuration)
|
||||
token.expirationDate(new Date(currentTime+tokenDuration))
|
||||
token.insertDate(new Date(currentTime))
|
||||
val tokenSaved = token.save()
|
||||
|
||||
nonceSaved && tokenSaved
|
||||
}
|
||||
|
||||
def getUser : Box[User] = {
|
||||
val httpMethod = S.request match {
|
||||
case Full(r) => r.request.method
|
||||
case _ => "GET"
|
||||
}
|
||||
val (httpCode, message, oAuthParameters) = validator("protectedResource", httpMethod)
|
||||
|
||||
//TODO: Needs refactoring
|
||||
if(httpCode== 200) getUser(httpCode, oAuthParameters.get("oauth_token"))
|
||||
else Failure(message)
|
||||
}
|
||||
|
||||
def getUser(httpCode : Int, tokenID : Box[String]) : Box[User] =
|
||||
if(httpCode==200)
|
||||
{
|
||||
import code.model.Token
|
||||
logger.info("OAuth header correct ")
|
||||
Token.find(By(Token.key, tokenID.get)) match {
|
||||
case Full(token) => {
|
||||
logger.info("access token: "+ token + " found")
|
||||
val user = User.findById(token.userId.get)
|
||||
//just a log
|
||||
user match {
|
||||
case Full(u) => logger.info("user " + u.emailAddress + " was found from the oauth token")
|
||||
case _ => logger.info("no user was found for the oauth token")
|
||||
}
|
||||
user
|
||||
}
|
||||
case _ =>{
|
||||
logger.warn("no token " + tokenID.get + " found")
|
||||
Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Empty
|
||||
}
|
||||
546
MavLift/src/main/scala/code/api/v1_2/JSONFactory.scala
Normal file
546
MavLift/src/main/scala/code/api/v1_2/JSONFactory.scala
Normal file
@ -0,0 +1,546 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.api.v1_2
|
||||
|
||||
import java.util.Date
|
||||
import net.liftweb.common.{Box, Full}
|
||||
import code.model._
|
||||
|
||||
case class APIInfoJSON(
|
||||
version : String,
|
||||
git_commit : String,
|
||||
hosted_by : HostedBy
|
||||
)
|
||||
case class HostedBy(
|
||||
organisation : String,
|
||||
email : String,
|
||||
phone : String
|
||||
)
|
||||
case class ErrorMessage(
|
||||
error : String
|
||||
)
|
||||
case class SuccessMessage(
|
||||
success : String
|
||||
)
|
||||
case class BanksJSON(
|
||||
banks : List[BankJSON]
|
||||
)
|
||||
case class MinimalBankJSON(
|
||||
national_identifier : String,
|
||||
name : String
|
||||
)
|
||||
case class BankJSON(
|
||||
id : String,
|
||||
short_name : String,
|
||||
full_name : String,
|
||||
logo : String,
|
||||
website : String
|
||||
)
|
||||
case class ViewsJSON(
|
||||
views : List[ViewJSON]
|
||||
)
|
||||
case class ViewJSON(
|
||||
id : String,
|
||||
short_name : String,
|
||||
description : String,
|
||||
is_public : Boolean
|
||||
)
|
||||
case class AccountsJSON(
|
||||
accounts : List[AccountJSON]
|
||||
)
|
||||
case class AccountJSON(
|
||||
id : String,
|
||||
label : String,
|
||||
views_available : Set[ViewJSON],
|
||||
bank_id : String
|
||||
)
|
||||
case class ModeratedAccountJSON(
|
||||
id : String,
|
||||
label : String,
|
||||
number : String,
|
||||
owners : List[UserJSON],
|
||||
`type` : String,
|
||||
balance : AmountOfMoneyJSON,
|
||||
IBAN : String,
|
||||
views_available : Set[ViewJSON],
|
||||
bank_id : String
|
||||
)
|
||||
case class UserJSON(
|
||||
id : String,
|
||||
provider : String,
|
||||
display_name : String
|
||||
)
|
||||
case class PermissionsJSON(
|
||||
permissions : List[PermissionJSON]
|
||||
)
|
||||
case class PermissionJSON(
|
||||
user : UserJSON,
|
||||
views : List[ViewJSON]
|
||||
)
|
||||
case class AmountOfMoneyJSON(
|
||||
currency : String,
|
||||
amount : String
|
||||
)
|
||||
case class AccountHolderJSON(
|
||||
name : String,
|
||||
is_alias : Boolean
|
||||
)
|
||||
case class ThisAccountJSON(
|
||||
id : String,
|
||||
holders : List[AccountHolderJSON],
|
||||
number : String,
|
||||
kind : String,
|
||||
IBAN : String,
|
||||
bank : MinimalBankJSON
|
||||
)
|
||||
case class OtherAccountsJSON(
|
||||
other_accounts : List[OtherAccountJSON]
|
||||
)
|
||||
case class OtherAccountJSON(
|
||||
id : String,
|
||||
holder : AccountHolderJSON,
|
||||
number : String,
|
||||
kind : String,
|
||||
IBAN : String,
|
||||
bank : MinimalBankJSON,
|
||||
metadata : OtherAccountMetadataJSON
|
||||
)
|
||||
case class OtherAccountMetadataJSON(
|
||||
public_alias : String,
|
||||
private_alias : String,
|
||||
more_info : String,
|
||||
URL : String,
|
||||
image_URL : String,
|
||||
open_corporates_URL : String,
|
||||
corporate_location : LocationJSON,
|
||||
physical_location : LocationJSON
|
||||
)
|
||||
case class LocationJSON(
|
||||
latitude : Double,
|
||||
longitude : Double,
|
||||
date : Date,
|
||||
user : UserJSON
|
||||
)
|
||||
case class TransactionDetailsJSON(
|
||||
`type` : String,
|
||||
label : String,
|
||||
posted : Date,
|
||||
completed : Date,
|
||||
new_balance : AmountOfMoneyJSON,
|
||||
value : AmountOfMoneyJSON
|
||||
)
|
||||
case class TransactionMetadataJSON(
|
||||
narrative : String,
|
||||
comments : List[TransactionCommentJSON],
|
||||
tags : List[TransactionTagJSON],
|
||||
images : List[TransactionImageJSON],
|
||||
where : LocationJSON
|
||||
)
|
||||
case class TransactionsJSON(
|
||||
transactions: List[TransactionJSON]
|
||||
)
|
||||
case class TransactionJSON(
|
||||
id : String,
|
||||
this_account : ThisAccountJSON,
|
||||
other_account : OtherAccountJSON,
|
||||
details : TransactionDetailsJSON,
|
||||
metadata : TransactionMetadataJSON
|
||||
)
|
||||
case class TransactionImagesJSON(
|
||||
images : List[TransactionImageJSON]
|
||||
)
|
||||
case class TransactionImageJSON(
|
||||
id : String,
|
||||
label : String,
|
||||
URL : String,
|
||||
date : Date,
|
||||
user : UserJSON
|
||||
)
|
||||
case class PostTransactionImageJSON(
|
||||
label : String,
|
||||
URL : String
|
||||
)
|
||||
case class PostTransactionCommentJSON(
|
||||
value: String
|
||||
)
|
||||
case class PostTransactionTagJSON(
|
||||
value : String
|
||||
)
|
||||
case class TransactionTagJSON(
|
||||
id : String,
|
||||
value : String,
|
||||
date : Date,
|
||||
user : UserJSON
|
||||
)
|
||||
case class TransactionTagsJSON(
|
||||
tags: List[TransactionTagJSON]
|
||||
)
|
||||
case class TransactionCommentJSON(
|
||||
id : String,
|
||||
value : String,
|
||||
date: Date,
|
||||
user : UserJSON
|
||||
)
|
||||
case class TransactionCommentsJSON(
|
||||
comments: List[TransactionCommentJSON]
|
||||
)
|
||||
case class TransactionWhereJSON(
|
||||
where: LocationJSON
|
||||
)
|
||||
case class PostTransactionWhereJSON(
|
||||
where: LocationPlainJSON
|
||||
)
|
||||
case class AliasJSON(
|
||||
alias: String
|
||||
)
|
||||
case class MoreInfoJSON(
|
||||
more_info: String
|
||||
)
|
||||
case class UrlJSON(
|
||||
URL:String
|
||||
)
|
||||
case class ImageUrlJSON(
|
||||
image_URL: String
|
||||
)
|
||||
case class OpenCorporateUrlJSON(
|
||||
open_corporates_URL: String
|
||||
)
|
||||
case class CorporateLocationJSON(
|
||||
corporate_location: LocationPlainJSON
|
||||
)
|
||||
case class PhysicalLocationJSON(
|
||||
physical_location: LocationPlainJSON
|
||||
)
|
||||
case class LocationPlainJSON(
|
||||
latitude : Double,
|
||||
longitude : Double
|
||||
)
|
||||
case class TransactionNarrativeJSON(
|
||||
narrative : String
|
||||
)
|
||||
|
||||
case class ViewIdsJson(
|
||||
views : List[String]
|
||||
)
|
||||
|
||||
object JSONFactory{
|
||||
def stringOrNull(text : String) =
|
||||
if(text.isEmpty)
|
||||
null
|
||||
else
|
||||
text
|
||||
|
||||
def stringOptionOrNull(text : Option[String]) =
|
||||
text match {
|
||||
case Some(t) => stringOrNull(t)
|
||||
case _ => null
|
||||
}
|
||||
|
||||
def createBankJSON(bank : Bank) : BankJSON = {
|
||||
new BankJSON(
|
||||
stringOrNull(bank.permalink),
|
||||
stringOrNull(bank.shortName),
|
||||
stringOrNull(bank.fullName),
|
||||
stringOrNull(bank.logoURL),
|
||||
stringOrNull(bank.website)
|
||||
)
|
||||
}
|
||||
|
||||
def createViewsJSON(views : List[View]) : ViewsJSON = {
|
||||
val list : List[ViewJSON] = views.map(createViewJSON)
|
||||
new ViewsJSON(list)
|
||||
}
|
||||
|
||||
def createViewJSON(view : View) : ViewJSON = {
|
||||
new ViewJSON(
|
||||
view.permalink,
|
||||
stringOrNull(view.name),
|
||||
stringOrNull(view.description),
|
||||
view.isPublic
|
||||
)
|
||||
}
|
||||
|
||||
def createAccountJSON(account : BankAccount, viewsAvailable : Set[ViewJSON] ) : AccountJSON = {
|
||||
new AccountJSON(
|
||||
account.permalink,
|
||||
stringOrNull(account.label),
|
||||
viewsAvailable,
|
||||
account.bankPermalink
|
||||
)
|
||||
}
|
||||
|
||||
def createBankAccountJSON(account : ModeratedBankAccount, viewsAvailable : Set[ViewJSON]) : ModeratedAccountJSON = {
|
||||
val bankName = account.bankName.getOrElse("")
|
||||
new ModeratedAccountJSON(
|
||||
account.id,
|
||||
stringOptionOrNull(account.label),
|
||||
stringOptionOrNull(account.number),
|
||||
createOwnersJSON(account.owners.getOrElse(Set()), bankName),
|
||||
stringOptionOrNull(account.accountType),
|
||||
createAmountOfMoneyJSON(account.currency.getOrElse(""), account.balance),
|
||||
stringOptionOrNull(account.iban),
|
||||
viewsAvailable,
|
||||
stringOptionOrNull(account.bankPermalink)
|
||||
)
|
||||
}
|
||||
|
||||
def createTransactionsJSON(transactions: List[ModeratedTransaction]) : TransactionsJSON = {
|
||||
new TransactionsJSON(transactions.map(createTransactionJSON))
|
||||
}
|
||||
|
||||
def createTransactionJSON(transaction : ModeratedTransaction) : TransactionJSON = {
|
||||
new TransactionJSON(
|
||||
id = transaction.id,
|
||||
this_account = transaction.bankAccount.map(createThisAccountJSON).getOrElse(null),
|
||||
other_account = transaction.otherBankAccount.map(createOtherBankAccount).getOrElse(null),
|
||||
details = createTransactionDetailsJSON(transaction),
|
||||
metadata = transaction.metadata.map(createTransactionMetadataJSON).getOrElse(null)
|
||||
)
|
||||
}
|
||||
|
||||
def createTransactionCommentsJSON(comments : List[Comment]) : TransactionCommentsJSON = {
|
||||
new TransactionCommentsJSON(comments.map(createTransactionCommentJSON))
|
||||
}
|
||||
|
||||
def createTransactionCommentJSON(comment : Comment) : TransactionCommentJSON = {
|
||||
new TransactionCommentJSON(
|
||||
id = comment.id_,
|
||||
value = comment.text,
|
||||
date = comment.datePosted,
|
||||
user = createUserJSON(comment.postedBy)
|
||||
)
|
||||
}
|
||||
|
||||
def createTransactionImagesJSON(images : List[TransactionImage]) : TransactionImagesJSON = {
|
||||
new TransactionImagesJSON(images.map(createTransactionImageJSON))
|
||||
}
|
||||
|
||||
def createTransactionImageJSON(image : TransactionImage) : TransactionImageJSON = {
|
||||
new TransactionImageJSON(
|
||||
id = image.id_,
|
||||
label = image.description,
|
||||
URL = image.imageUrl.toString,
|
||||
date = image.datePosted,
|
||||
user = createUserJSON(image.postedBy)
|
||||
)
|
||||
}
|
||||
|
||||
def createTransactionTagsJSON(tags : List[Tag]) : TransactionTagsJSON = {
|
||||
new TransactionTagsJSON(tags.map(createTransactionTagJSON))
|
||||
}
|
||||
|
||||
def createTransactionTagJSON(tag : Tag) : TransactionTagJSON = {
|
||||
new TransactionTagJSON(
|
||||
id = tag.id_,
|
||||
value = tag.value,
|
||||
date = tag.datePosted,
|
||||
user = createUserJSON(tag.postedBy)
|
||||
)
|
||||
}
|
||||
|
||||
def createLocationJSON(location : GeoTag) : LocationJSON = {
|
||||
val user = createUserJSON(location.postedBy)
|
||||
//test if the GeoTag is set to its default value
|
||||
if(location.latitude == 0.0 & location.longitude == 0.0 & user == null)
|
||||
null
|
||||
else
|
||||
new LocationJSON(
|
||||
latitude = location.latitude,
|
||||
longitude = location.longitude,
|
||||
date = location.datePosted,
|
||||
user = user
|
||||
)
|
||||
}
|
||||
|
||||
def createLocationPlainJSON(lat: Double, lon: Double) : LocationPlainJSON = {
|
||||
new LocationPlainJSON(
|
||||
latitude = lat,
|
||||
longitude = lon
|
||||
)
|
||||
}
|
||||
|
||||
def createTransactionMetadataJSON(metadata : ModeratedTransactionMetadata) : TransactionMetadataJSON = {
|
||||
new TransactionMetadataJSON(
|
||||
narrative = stringOptionOrNull(metadata.ownerComment),
|
||||
comments = metadata.comments.map(_.map(createTransactionCommentJSON)).getOrElse(null),
|
||||
tags = metadata.tags.map(_.map(createTransactionTagJSON)).getOrElse(null),
|
||||
images = metadata.images.map(_.map(createTransactionImageJSON)).getOrElse(null),
|
||||
where = metadata.whereTag.map(createLocationJSON).getOrElse(null)
|
||||
)
|
||||
}
|
||||
|
||||
def createTransactionDetailsJSON(transaction : ModeratedTransaction) : TransactionDetailsJSON = {
|
||||
new TransactionDetailsJSON(
|
||||
`type` = stringOptionOrNull(transaction.transactionType),
|
||||
label = stringOptionOrNull(transaction.label),
|
||||
posted = transaction.startDate.getOrElse(null),
|
||||
completed = transaction.finishDate.getOrElse(null),
|
||||
new_balance = createAmountOfMoneyJSON(transaction.currency, transaction.balance),
|
||||
value= createAmountOfMoneyJSON(transaction.currency, transaction.amount.map(_.toString))
|
||||
)
|
||||
}
|
||||
|
||||
def createMinimalBankJSON(bankAccount : ModeratedBankAccount) : MinimalBankJSON = {
|
||||
new MinimalBankJSON(
|
||||
national_identifier = stringOptionOrNull(bankAccount.nationalIdentifier),
|
||||
name = stringOptionOrNull(bankAccount.bankName)
|
||||
)
|
||||
}
|
||||
|
||||
def createMinimalBankJSON(bankAccount : ModeratedOtherBankAccount) : MinimalBankJSON = {
|
||||
new MinimalBankJSON(
|
||||
national_identifier = stringOptionOrNull(bankAccount.nationalIdentifier),
|
||||
name = stringOptionOrNull(bankAccount.bankName)
|
||||
)
|
||||
}
|
||||
|
||||
def createThisAccountJSON(bankAccount : ModeratedBankAccount) : ThisAccountJSON = {
|
||||
new ThisAccountJSON(
|
||||
id = bankAccount.id,
|
||||
number = stringOptionOrNull(bankAccount.number),
|
||||
kind = stringOptionOrNull(bankAccount.accountType),
|
||||
IBAN = stringOptionOrNull(bankAccount.iban),
|
||||
bank = createMinimalBankJSON(bankAccount),
|
||||
holders = null //TODO //bankAccount.owners.map(x => x.toList.map(h => createAccountHolderJSON(h, ??))).getOrElse(null)
|
||||
)
|
||||
}
|
||||
|
||||
def createAccountHolderJSON(owner : AccountOwner, isAlias : Boolean) : AccountHolderJSON = {
|
||||
new AccountHolderJSON(
|
||||
name = owner.name,
|
||||
is_alias = isAlias
|
||||
)
|
||||
}
|
||||
|
||||
def createAccountHolderJSON(name : String, isAlias : Boolean) : AccountHolderJSON = {
|
||||
new AccountHolderJSON(
|
||||
name = name,
|
||||
is_alias = isAlias
|
||||
)
|
||||
}
|
||||
|
||||
def createOtherAccountMetaDataJSON(metadata : ModeratedOtherBankAccountMetadata) : OtherAccountMetadataJSON = {
|
||||
new OtherAccountMetadataJSON(
|
||||
public_alias = stringOptionOrNull(metadata.publicAlias),
|
||||
private_alias = stringOptionOrNull(metadata.privateAlias),
|
||||
more_info = stringOptionOrNull(metadata.moreInfo),
|
||||
URL = stringOptionOrNull(metadata.url),
|
||||
image_URL = stringOptionOrNull(metadata.imageURL),
|
||||
open_corporates_URL = stringOptionOrNull(metadata.openCorporatesURL),
|
||||
corporate_location = metadata.corporateLocation.map(createLocationJSON).getOrElse(null),
|
||||
physical_location = metadata.physicalLocation.map(createLocationJSON).getOrElse(null)
|
||||
)
|
||||
}
|
||||
|
||||
def createOtherBankAccount(bankAccount : ModeratedOtherBankAccount) : OtherAccountJSON = {
|
||||
new OtherAccountJSON(
|
||||
id = bankAccount.id,
|
||||
number = stringOptionOrNull(bankAccount.number),
|
||||
kind = stringOptionOrNull(bankAccount.kind),
|
||||
IBAN = stringOptionOrNull(bankAccount.iban),
|
||||
bank = createMinimalBankJSON(bankAccount),
|
||||
holder = createAccountHolderJSON(bankAccount.label.display, bankAccount.isAlias),
|
||||
metadata = bankAccount.metadata.map(createOtherAccountMetaDataJSON).getOrElse(null)
|
||||
)
|
||||
}
|
||||
|
||||
def createOtherBankAccountsJSON(otherBankAccounts : List[ModeratedOtherBankAccount]) : OtherAccountsJSON = {
|
||||
val otherAccountsJSON : List[OtherAccountJSON] = otherBankAccounts.map(createOtherBankAccount)
|
||||
OtherAccountsJSON(otherAccountsJSON)
|
||||
}
|
||||
|
||||
def createUserJSON(user : User) : UserJSON = {
|
||||
new UserJSON(
|
||||
user.id_,
|
||||
stringOrNull(user.provider),
|
||||
stringOrNull(user.emailAddress)
|
||||
)
|
||||
}
|
||||
|
||||
def createUserJSON(user : Box[User]) : UserJSON = {
|
||||
user match {
|
||||
case Full(u) => createUserJSON(u)
|
||||
case _ => null
|
||||
}
|
||||
}
|
||||
|
||||
def createOwnersJSON(owners : Set[AccountOwner], bankName : String) : List[UserJSON] = {
|
||||
owners.map(o => {
|
||||
new UserJSON(
|
||||
o.id,
|
||||
stringOrNull(bankName),
|
||||
stringOrNull(o.name)
|
||||
)
|
||||
}
|
||||
).toList
|
||||
}
|
||||
|
||||
def createAmountOfMoneyJSON(currency : String, amount : String) : AmountOfMoneyJSON = {
|
||||
new AmountOfMoneyJSON(
|
||||
stringOrNull(currency),
|
||||
stringOrNull(amount)
|
||||
)
|
||||
}
|
||||
|
||||
def createAmountOfMoneyJSON(currency : Option[String], amount : Option[String]) : AmountOfMoneyJSON = {
|
||||
new AmountOfMoneyJSON(
|
||||
stringOptionOrNull(currency),
|
||||
stringOptionOrNull(amount)
|
||||
)
|
||||
}
|
||||
|
||||
def createAmountOfMoneyJSON(currency : Option[String], amount : String) : AmountOfMoneyJSON = {
|
||||
new AmountOfMoneyJSON(
|
||||
stringOptionOrNull(currency),
|
||||
stringOrNull(amount)
|
||||
)
|
||||
}
|
||||
|
||||
def createPermissionsJSON(permissions : List[Permission]) : PermissionsJSON = {
|
||||
val permissionsJson = permissions.map(p => {
|
||||
new PermissionJSON(
|
||||
createUserJSON(p.user),
|
||||
p.views.map(createViewJSON)
|
||||
)
|
||||
})
|
||||
new PermissionsJSON(permissionsJson)
|
||||
}
|
||||
|
||||
def createAliasJSON(alias: String): AliasJSON = {
|
||||
AliasJSON(stringOrNull(alias))
|
||||
}
|
||||
|
||||
def createTransactionNarrativeJSON(narrative: String): TransactionNarrativeJSON = {
|
||||
TransactionNarrativeJSON(stringOrNull(narrative))
|
||||
}
|
||||
|
||||
}
|
||||
1175
MavLift/src/main/scala/code/api/v1_2/OBPAPI1.2.scala
Normal file
1175
MavLift/src/main/scala/code/api/v1_2/OBPAPI1.2.scala
Normal file
File diff suppressed because it is too large
Load Diff
365
MavLift/src/main/scala/code/model/BankingData.scala
Normal file
365
MavLift/src/main/scala/code/model/BankingData.scala
Normal file
@ -0,0 +1,365 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.model
|
||||
|
||||
import scala.math.BigDecimal
|
||||
import java.util.Date
|
||||
import scala.collection.immutable.Set
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.JObject
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.JsonAST.JArray
|
||||
import net.liftweb.common._
|
||||
import code.model.dataAccess.{LocalStorage, Account, HostedBank}
|
||||
import code.model.dataAccess.OBPEnvelope.OBPQueryParam
|
||||
|
||||
|
||||
class Bank(
|
||||
val id: String,
|
||||
val shortName : String,
|
||||
val fullName : String,
|
||||
val permalink : String,
|
||||
val logoURL : String,
|
||||
val website : String
|
||||
)
|
||||
{
|
||||
def accounts(user : Box[User]) : Box[List[BankAccount]] = {
|
||||
user match {
|
||||
case Full(u) => nonPublicAccounts(u)
|
||||
case _ => publicAccounts
|
||||
}
|
||||
}
|
||||
|
||||
def publicAccounts : Box[List[BankAccount]] = LocalStorage.getPublicBankAccounts(this)
|
||||
def nonPublicAccounts(user : User) : Box[List[BankAccount]] = {
|
||||
LocalStorage.getNonPublicBankAccounts(user, id)
|
||||
}
|
||||
|
||||
def detailedJson : JObject = {
|
||||
("name" -> shortName) ~
|
||||
("website" -> "") ~
|
||||
("email" -> "")
|
||||
}
|
||||
|
||||
def toJson : JObject = {
|
||||
("alias" -> permalink) ~
|
||||
("name" -> shortName) ~
|
||||
("logo" -> "") ~
|
||||
("links" -> linkJson)
|
||||
}
|
||||
|
||||
def linkJson : JObject = {
|
||||
("rel" -> "bank") ~
|
||||
("href" -> {"/" + permalink + "/bank"}) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> {"Get information about the bank identified by " + permalink})
|
||||
}
|
||||
}
|
||||
|
||||
object Bank {
|
||||
def apply(bankPermalink: String) : Box[Bank] = LocalStorage.getBank(bankPermalink)
|
||||
|
||||
def all : List[Bank] = LocalStorage.allBanks
|
||||
|
||||
def toJson(banks: Seq[Bank]) : JArray =
|
||||
banks.map(bank => bank.toJson)
|
||||
|
||||
}
|
||||
|
||||
class AccountOwner(
|
||||
val id : String,
|
||||
val name : String
|
||||
)
|
||||
|
||||
class BankAccount(
|
||||
val id : String,
|
||||
val owners : Set[AccountOwner],
|
||||
val accountType : String,
|
||||
val balance : BigDecimal,
|
||||
val currency : String,
|
||||
val name : String,
|
||||
val label : String,
|
||||
val nationalIdentifier : String,
|
||||
val swift_bic : Option[String],
|
||||
val iban : Option[String],
|
||||
val allowAnnoymousAccess : Boolean,
|
||||
val number : String,
|
||||
val bankName : String,
|
||||
val bankPermalink : String,
|
||||
val permalink : String
|
||||
) extends Loggable{
|
||||
|
||||
private def viewNotAllowed(view : View ) = Failure("user does not have access to the " + view.name + " view")
|
||||
|
||||
def permittedViews(user: Box[User]) : Set[View] = {
|
||||
user match {
|
||||
case Full(u) => u.permittedViews(this)
|
||||
case _ =>{
|
||||
logger.info("no user was found in the permittedViews")
|
||||
if(this.allowPublicAccess) Set(Public) else Set()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def allowPublicAccess = allowAnnoymousAccess
|
||||
|
||||
/**
|
||||
* @param the view that we want test the access to
|
||||
* @param the user that we want to see if he has access to the view or not
|
||||
* @return true if the user is allowed to access this view, false otherwise
|
||||
*/
|
||||
def authorizedAccess(view: View, user: Option[User]) : Boolean = {
|
||||
view match {
|
||||
case Public => allowPublicAccess
|
||||
case _ => user match {
|
||||
case Some(u) => {
|
||||
u.permittedViews(this).contains(view)
|
||||
}
|
||||
case None => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param a user requesting to see the other users' permissions
|
||||
* @return a Box of all the users' permissions of this bank account if the user passed as a parameter has access to the owner view (allowed to see this kind of data)
|
||||
*/
|
||||
def permissions(user : User) : Box[List[Permission]] = {
|
||||
//check if the user have access to the owner view in this the account
|
||||
if(authorizedAccess(Owner,Full(user)))
|
||||
LocalStorage.permissions(this)
|
||||
else
|
||||
Failure("user : " + user.emailAddress + "don't have access to owner view on account " + id, Empty, Empty)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param a user that want to grant an other user access to a view
|
||||
* @param the id of the view that we want to grant access
|
||||
* @param the id of the other user that we want grant access
|
||||
* @return a Full(true) if everything is okay, a Failure otherwise
|
||||
*/
|
||||
def addPermission(user : User, viewId : String, otherUserId : String) : Box[Boolean] = {
|
||||
//check if the user have access to the owner view in this the account
|
||||
if(authorizedAccess(Owner,Full(user)))
|
||||
for{
|
||||
view <- View.fromUrl(viewId) //check if the viewId corresponds to a view
|
||||
otherUser <- User.findById(otherUserId) //check if the userId corresponds to a user
|
||||
isSaved <- LocalStorage.addPermission(id, view, otherUser) ?~ "could not save the privilege"
|
||||
} yield isSaved
|
||||
else
|
||||
Failure("user : " + user.emailAddress + "don't have access to owner view on account " + id, Empty, Empty)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param a user that want to grant an other user access to a list views
|
||||
* @param the list of views ids that we want to grant access
|
||||
* @param the id of the other user that we want grant access
|
||||
* @return a the list of the granted views if everything is okay, a Failure otherwise
|
||||
*/
|
||||
def addPermissions(user : User, viewIds : List[String], otherUserId : String) : Box[List[View]] = {
|
||||
//we try to get all the views that correspond to that list of view ids
|
||||
lazy val viewBoxes = viewIds.map(View.fromUrl)
|
||||
//we see if the the is Failures
|
||||
lazy val failureList = viewBoxes.collect(v => {
|
||||
v match {
|
||||
case x : Failure => x
|
||||
}
|
||||
})
|
||||
|
||||
lazy val viewsFormIds : Box[List[View]] =
|
||||
//if no failures then we return the Full views
|
||||
if(failureList.size == 0)
|
||||
Full(viewBoxes.flatten)
|
||||
else
|
||||
//we return just the first failure
|
||||
failureList.head
|
||||
|
||||
//check if the user have access to the owner view in this the account
|
||||
if(authorizedAccess(Owner,Full(user)))
|
||||
for{
|
||||
otherUser <- User.findById(otherUserId) //check if the userId corresponds to a user
|
||||
views <- viewsFormIds
|
||||
grantedViews <- LocalStorage.addPermissions(id, views, otherUser) ?~ "could not save the privilege"
|
||||
} yield views
|
||||
else
|
||||
Failure("user : " + user.emailAddress + "don't have access to owner view on account " + id, Empty, Empty)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param a user that want to revoke an other user access to a view
|
||||
* @param the id of the view that we want to revoke access
|
||||
* @param the id of the other user that we want revoke access
|
||||
* @return a Full(true) if everything is okay, a Failure otherwise
|
||||
*/
|
||||
def revokePermission(user : User, viewId : String, otherUserId : String) : Box[Boolean] = {
|
||||
//check if the user have access to the owner view in this the account
|
||||
if(authorizedAccess(Owner,Full(user)))
|
||||
for{
|
||||
view <- View.fromUrl(viewId) //check if the viewId corresponds to a view
|
||||
otherUser <- User.findById(otherUserId) //check if the userId corresponds to a user
|
||||
isRevoked <- LocalStorage.revokePermission(id, view, otherUser) ?~ "could not revoke the privilege"
|
||||
} yield isRevoked
|
||||
else
|
||||
Failure("user : " + user.emailAddress + " don't have access to owner view on account " + id, Empty, Empty)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param a user that want to revoke an other user access to a view
|
||||
* @param the id of the other user that we want revoke access
|
||||
* @return a Full(true) if everything is okay, a Failure otherwise
|
||||
*/
|
||||
|
||||
def revokeAllPermission(user : User, otherUserId : String) : Box[Boolean] = {
|
||||
//check if the user have access to the owner view in this the account
|
||||
if(authorizedAccess(Owner,Full(user)))
|
||||
for{
|
||||
otherUser <- User.findById(otherUserId) //check if the userId corresponds to a user
|
||||
isRevoked <- LocalStorage.revokeAllPermission(id, otherUser) ?~ "could not revoke the privileges"
|
||||
} yield isRevoked
|
||||
else
|
||||
Failure("user : " + user.emailAddress + " don't have access to owner view on account " + id, Empty, Empty)
|
||||
}
|
||||
|
||||
def views(user : User) : Box[List[View]] = {
|
||||
//check if the user have access to the owner view in this the account
|
||||
if(authorizedAccess(Owner,Full(user)))
|
||||
for{
|
||||
isRevoked <- LocalStorage.views(id) ?~ "could not get the views"
|
||||
} yield isRevoked
|
||||
else
|
||||
Failure("user : " + user.emailAddress + " don't have access to owner view on account " + id, Empty, Empty)
|
||||
}
|
||||
|
||||
def moderatedTransaction(id: String, view: View, user: Box[User]) : Box[ModeratedTransaction] = {
|
||||
if(authorizedAccess(view, user))
|
||||
LocalStorage.getModeratedTransaction(id, bankPermalink, permalink)(view.moderate)
|
||||
else
|
||||
viewNotAllowed(view)
|
||||
}
|
||||
|
||||
def getModeratedTransactions(user : Box[User], view : View, queryParams: OBPQueryParam*): Box[List[ModeratedTransaction]] = {
|
||||
if(authorizedAccess(view, user))
|
||||
LocalStorage.getModeratedTransactions(permalink, bankPermalink, queryParams: _*)(view.moderate)
|
||||
else
|
||||
viewNotAllowed(view)
|
||||
}
|
||||
|
||||
def moderatedBankAccount(view: View, user: Box[User]) : Box[ModeratedBankAccount] = {
|
||||
if(authorizedAccess(view, user))
|
||||
//implicit conversion from option to box
|
||||
view.moderate(this)
|
||||
else
|
||||
viewNotAllowed(view)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param the view that we will use to get the ModeratedOtherBankAccount list
|
||||
* @param the user that want access to the ModeratedOtherBankAccount list
|
||||
* @return a Box of a list ModeratedOtherBankAccounts, it the bank
|
||||
* accounts that have at least one transaction in common with this bank account
|
||||
*/
|
||||
def moderatedOtherBankAccounts(view : View, user : Box[User]) : Box[List[ModeratedOtherBankAccount]] = {
|
||||
if(authorizedAccess(view, user))
|
||||
LocalStorage.getModeratedOtherBankAccounts(id)(view.moderate)
|
||||
else
|
||||
viewNotAllowed(view)
|
||||
}
|
||||
/**
|
||||
* @param the ID of the other bank account that the user want have access
|
||||
* @param the view that we will use to get the ModeratedOtherBankAccount
|
||||
* @param the user that want access to the otherBankAccounts list
|
||||
* @return a Box of a ModeratedOtherBankAccounts, it a bank
|
||||
* account that have at least one transaction in common with this bank account
|
||||
*/
|
||||
def moderatedOtherBankAccount(otherAccountID : String, view : View, user : Box[User]) : Box[ModeratedOtherBankAccount] =
|
||||
if(authorizedAccess(view, user))
|
||||
LocalStorage.getModeratedOtherBankAccount(id, otherAccountID)(view.moderate)
|
||||
else
|
||||
viewNotAllowed(view)
|
||||
|
||||
def overviewJson(user: Box[User]): JObject = {
|
||||
val views = permittedViews(user)
|
||||
("number" -> number) ~
|
||||
("account_alias" -> label) ~
|
||||
("owner_description" -> "") ~
|
||||
("views_available" -> views.map(view => view.toJson)) ~
|
||||
View.linksJson(views, permalink, bankPermalink)
|
||||
}
|
||||
}
|
||||
|
||||
object BankAccount {
|
||||
def apply(bankpermalink: String, bankAccountPermalink: String) : Box[BankAccount] = {
|
||||
LocalStorage.getBankAccount(bankpermalink, bankAccountPermalink)
|
||||
}
|
||||
|
||||
def publicAccounts : List[BankAccount] = {
|
||||
LocalStorage.getAllPublicAccounts()
|
||||
}
|
||||
}
|
||||
|
||||
class OtherBankAccount(
|
||||
val id : String,
|
||||
val label : String,
|
||||
val nationalIdentifier : String,
|
||||
//the bank international identifier
|
||||
val swift_bic : Option[String],
|
||||
//the international account identifier
|
||||
val iban : Option[String],
|
||||
val number : String,
|
||||
val bankName : String,
|
||||
val metadata : OtherBankAccountMetadata,
|
||||
val kind : String
|
||||
)
|
||||
|
||||
class Transaction(
|
||||
//A universally unique id
|
||||
val uuid : String,
|
||||
//The bank's id for the transaction
|
||||
val id : String,
|
||||
val thisAccount : BankAccount,
|
||||
val otherAccount : OtherBankAccount,
|
||||
val metadata : TransactionMetadata,
|
||||
//E.g. cash withdrawal, electronic payment, etc.
|
||||
val transactionType : String,
|
||||
val amount : BigDecimal,
|
||||
//ISO 4217, e.g. EUR, GBP, USD, etc.
|
||||
val currency : String,
|
||||
// Bank provided comment
|
||||
val label : Option[String],
|
||||
// The date the transaction was initiated
|
||||
val startDate : Date,
|
||||
// The date when the money finished changing hands
|
||||
val finishDate : Date,
|
||||
//the new balance for the bank account
|
||||
val balance : BigDecimal
|
||||
)
|
||||
199
MavLift/src/main/scala/code/model/Metadata.scala
Normal file
199
MavLift/src/main/scala/code/model/Metadata.scala
Normal file
@ -0,0 +1,199 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model
|
||||
import java.util.Date
|
||||
import java.net.URL
|
||||
import net.liftweb.common.{Box,Full}
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
import net.liftweb.json.JsonDSL._
|
||||
|
||||
|
||||
trait Comment {
|
||||
def id_ : String
|
||||
// The person that posted the comment
|
||||
def postedBy : Box[User]
|
||||
|
||||
//the id of the view related to the comment
|
||||
def viewId : Long
|
||||
|
||||
// The actual text of the comment
|
||||
def text : String
|
||||
|
||||
def datePosted : Date
|
||||
|
||||
//if this is a reply, the id of the original comment
|
||||
def replyToID : String
|
||||
|
||||
def toJson : JObject = {
|
||||
val userInJson = postedBy match {
|
||||
case Full(user) => user.toJson
|
||||
case _ => ("id" -> "") ~
|
||||
("provider" -> "") ~
|
||||
("display_name" -> "")
|
||||
}
|
||||
|
||||
("id" -> id_) ~
|
||||
("date" -> datePosted.toString) ~
|
||||
("comment" -> text) ~
|
||||
("view" -> viewId) ~
|
||||
("user" -> userInJson) ~
|
||||
("reply_to" -> "")
|
||||
}
|
||||
}
|
||||
|
||||
trait Tag {
|
||||
|
||||
def id_ : String
|
||||
def datePosted : Date
|
||||
def postedBy : Box[User]
|
||||
def viewId : Long
|
||||
def value : String
|
||||
}
|
||||
|
||||
trait GeoTag {
|
||||
|
||||
def datePosted : Date
|
||||
def postedBy : Box[User]
|
||||
def viewId : Long
|
||||
def longitude : Double
|
||||
def latitude : Double
|
||||
}
|
||||
|
||||
trait TransactionImage {
|
||||
|
||||
def id_ : String
|
||||
def datePosted : Date
|
||||
def postedBy : Box[User]
|
||||
def viewId : Long
|
||||
def description : String
|
||||
def imageUrl : URL
|
||||
}
|
||||
|
||||
class OtherBankAccountMetadata(
|
||||
val publicAlias : String,
|
||||
val privateAlias : String,
|
||||
val moreInfo : String,
|
||||
val url : String,
|
||||
val imageURL : String,
|
||||
val openCorporatesURL : String,
|
||||
val corporateLocation : GeoTag,
|
||||
val physicalLocation : GeoTag,
|
||||
val addMoreInfo : (String) => Boolean,
|
||||
val addURL : (String) => Boolean,
|
||||
val addImageURL : (String) => Boolean,
|
||||
val addOpenCorporatesURL : (String) => Boolean,
|
||||
|
||||
/**
|
||||
* @param: userId
|
||||
* @param: viewId
|
||||
* @param: datePosted
|
||||
* @param: longitude
|
||||
* @param: latitude
|
||||
*/
|
||||
val addCorporateLocation : (String, Long, Date, Double, Double) => Boolean,
|
||||
val deleteCorporateLocation : () => Boolean,
|
||||
/**
|
||||
* @param: userId
|
||||
* @param: viewId
|
||||
* @param: datePosted
|
||||
* @param: longitude
|
||||
* @param: latitude
|
||||
*/
|
||||
val addPhysicalLocation : (String, Long, Date, Double, Double) => Boolean,
|
||||
val deletePhysicalLocation : () => Boolean,
|
||||
val addPublicAlias : (String) => Boolean,
|
||||
val addPrivateAlias : (String) => Boolean
|
||||
)
|
||||
|
||||
class TransactionMetadata(
|
||||
val ownerComment : String,
|
||||
val addOwnerComment : String => Unit,
|
||||
val comments: List[Comment],
|
||||
/**
|
||||
* @param: userId
|
||||
* @param: viewId
|
||||
* @param: text
|
||||
* @param: datePosted
|
||||
*/
|
||||
val addComment : (String,Long, String, Date) => Comment,
|
||||
/**
|
||||
* @param: commentId
|
||||
*/
|
||||
val deleteComment : (String) => Box[Unit],
|
||||
|
||||
val tags: List[Tag],
|
||||
/**
|
||||
* @param: userId
|
||||
* @param: viewId
|
||||
* @param: tag
|
||||
* @param: datePosted
|
||||
*/
|
||||
val addTag: (String, Long, String, Date) => Tag,
|
||||
/**
|
||||
* @param: tagId
|
||||
*/
|
||||
val deleteTag : (String) => Box[Unit],
|
||||
val images : List[TransactionImage],
|
||||
/**
|
||||
* @param: userId
|
||||
* @param: viewId
|
||||
* @param: description
|
||||
* @param: datePosted
|
||||
* @param: imageURL
|
||||
*/
|
||||
val addImage : (String, Long, String, Date, URL) => TransactionImage,
|
||||
/**
|
||||
* @param: imageId
|
||||
*/
|
||||
val deleteImage : String => Unit,
|
||||
/**
|
||||
* @param: userId
|
||||
* @param: viewId
|
||||
* @param: datePosted
|
||||
* @param: longitude
|
||||
* @param: latitude
|
||||
*/
|
||||
val whereTags : List[GeoTag],
|
||||
/**
|
||||
* @param: userId
|
||||
* @param: viewId
|
||||
* @param: datePosted
|
||||
* @param: longitude
|
||||
* @param: latitude
|
||||
*/
|
||||
val addWhereTag : (String, Long, Date, Double, Double) => Boolean,
|
||||
/**
|
||||
* @param: viewId
|
||||
*/
|
||||
val deleteWhereTag : (Long) => Boolean
|
||||
)
|
||||
306
MavLift/src/main/scala/code/model/ModeratedBankingData.scala
Normal file
306
MavLift/src/main/scala/code/model/ModeratedBankingData.scala
Normal file
@ -0,0 +1,306 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model
|
||||
import java.util.Date
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
import net.liftweb.json.JsonAST.JString
|
||||
import net.liftweb.json.JsonAST.JField
|
||||
import net.liftweb.json._
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.http.JsonResponse
|
||||
import net.liftweb.http.LiftResponse
|
||||
import java.text.SimpleDateFormat
|
||||
import java.net.URL
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.common.Failure
|
||||
|
||||
|
||||
class ModeratedTransaction(
|
||||
val UUID : String,
|
||||
val id: String,
|
||||
val bankAccount: Option[ModeratedBankAccount],
|
||||
val otherBankAccount: Option[ModeratedOtherBankAccount],
|
||||
val metadata : Option[ModeratedTransactionMetadata],
|
||||
val transactionType: Option[String],
|
||||
val amount: Option[BigDecimal],
|
||||
val currency: Option[String],
|
||||
val label: Option[String],
|
||||
val startDate: Option[Date],
|
||||
val finishDate: Option[Date],
|
||||
//the filteredBlance type in this class is a string rather than Big decimal like in Transaction trait for snippet (display) reasons.
|
||||
//the view should be able to return a sign (- or +) or the real value. casting signs into bigdecimal is not possible
|
||||
val balance : String
|
||||
) {
|
||||
|
||||
def dateOption2JString(date: Option[Date]) : JString = {
|
||||
JString(date.map(d => ModeratedTransaction.dateFormat.format(d)) getOrElse "")
|
||||
}
|
||||
|
||||
def toJson(view: View): JObject = {
|
||||
("view" -> view.permalink) ~
|
||||
("uuid" -> id) ~
|
||||
("this_account" -> bankAccount) ~
|
||||
("other_account" -> otherBankAccount) ~
|
||||
("details" ->
|
||||
("type_en" -> transactionType) ~ //TODO: Need translations for transaction types and a way to
|
||||
("type_de" -> transactionType) ~ // figure out what language the original type is in
|
||||
("posted" -> dateOption2JString(startDate)) ~
|
||||
("completed" -> dateOption2JString(finishDate)) ~
|
||||
("new_balance" ->
|
||||
("currency" -> currency.getOrElse("")) ~
|
||||
("amount" -> balance)) ~
|
||||
("value" ->
|
||||
("currency" -> currency.getOrElse("")) ~
|
||||
("amount" -> amount)))
|
||||
}
|
||||
}
|
||||
|
||||
object ModeratedTransaction {
|
||||
val dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
|
||||
}
|
||||
|
||||
class ModeratedTransactionMetadata(
|
||||
val ownerComment : Option[String],
|
||||
val addOwnerComment : Option[(String => Unit)],
|
||||
val comments : Option[List[Comment]],
|
||||
val addComment: Option[(String, Long, String, Date) => Comment],
|
||||
private val deleteComment: Option[(String) => Box[Unit]],
|
||||
val tags : Option[List[Tag]],
|
||||
val addTag : Option[(String, Long, String, Date) => Tag],
|
||||
private val deleteTagFunc : Option[(String) => Box[Unit]],
|
||||
val images : Option[List[TransactionImage]],
|
||||
val addImage : Option[(String, Long, String, Date, URL) => TransactionImage],
|
||||
private val deleteImageFunc : Option[String => Unit],
|
||||
val whereTag : Option[GeoTag],
|
||||
val addWhereTag : Option[(String, Long, Date, Double, Double) => Boolean],
|
||||
private val deleteWhereTag : Option[(Long) => Boolean]
|
||||
){
|
||||
|
||||
@deprecated //TODO:This should be removed once SoFi is split from the API
|
||||
def deleteTag = deleteTagFunc
|
||||
|
||||
/**
|
||||
* @return Full if deleting the tag worked, or a failure message if it didn't
|
||||
*/
|
||||
def deleteTag(tagId : String, user: Option[User], bankAccount : BankAccount) : Box[Unit] = {
|
||||
for {
|
||||
tagList <- Box(tags) ?~ { "You must be able to see tags in order to delete them"}
|
||||
tag <- Box(tagList.find(tag => tag.id_ == tagId)) ?~ {"Tag with id " + tagId + "not found for this transaction"}
|
||||
deleteFunc <- if(tag.postedBy == user || bankAccount.authorizedAccess(Owner, user))
|
||||
Box(deleteTagFunc) ?~ "Deleting tags not permitted for this view"
|
||||
else
|
||||
Failure("deleting tags not permitted for the current user")
|
||||
tagIsDeleted <- deleteFunc(tagId)
|
||||
} yield {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@deprecated //This should be removed once SoFi is split from the API
|
||||
def deleteImage = deleteImageFunc
|
||||
|
||||
/**
|
||||
* @return Full if deleting the image worked, or a failure message if it didn't
|
||||
*/
|
||||
def deleteImage(imageId : String, user: Option[User], bankAccount : BankAccount) : Box[Unit] = {
|
||||
for {
|
||||
imageList <- Box(images) ?~ { "You must be able to see images in order to delete them"}
|
||||
image <- Box(imageList.find(image => image.id_ == imageId)) ?~ {"Image with id " + imageId + "not found for this transaction"}
|
||||
deleteFunc <- if(image.postedBy == user || bankAccount.authorizedAccess(Owner, user))
|
||||
Box(deleteImageFunc) ?~ "Deleting images not permitted for this view"
|
||||
else
|
||||
Failure("Deleting images not permitted for the current user")
|
||||
} yield {
|
||||
deleteFunc(imageId)
|
||||
}
|
||||
}
|
||||
|
||||
def deleteComment(commentId: String, user: Option[User],bankAccount: BankAccount) : Box[Unit] = {
|
||||
for {
|
||||
commentList <- Box(comments) ?~ {"You must be able to see comments in order to delete them"}
|
||||
comment <- Box(commentList.find(comment => comment.id_ == commentId)) ?~ {"Comment with id "+commentId+" not found for this transaction"}
|
||||
deleteFunc <- if(comment.postedBy == user || bankAccount.authorizedAccess(Owner, user))
|
||||
Box(deleteComment) ?~ "Deleting comments not permitted for this view"
|
||||
else
|
||||
Failure("Deleting comments not permitted for the current user")
|
||||
} yield {
|
||||
deleteFunc(commentId)
|
||||
}
|
||||
}
|
||||
|
||||
def deleteWhereTag(viewId: Long, user: Option[User],bankAccount: BankAccount) : Box[Boolean] = {
|
||||
for {
|
||||
whereTag <- Box(whereTag) ?~ {"You must be able to see the where tag in order to delete it"}
|
||||
deleteFunc <- if(whereTag.postedBy == user || bankAccount.authorizedAccess(Owner, user))
|
||||
Box(deleteWhereTag) ?~ "Deleting tag is not permitted for this view"
|
||||
else
|
||||
Failure("Deleting tags not permitted for the current user")
|
||||
} yield {
|
||||
deleteFunc(viewId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
object ModeratedTransactionMetadata {
|
||||
implicit def moderatedTransactionMetadata2Json(mTransactionMeta: ModeratedTransactionMetadata) : JObject = {
|
||||
JObject(JField("blah", JString("test")) :: Nil)
|
||||
}
|
||||
}
|
||||
|
||||
class ModeratedBankAccount(
|
||||
val id : String,
|
||||
val owners : Option[Set[AccountOwner]],
|
||||
val accountType : Option[String],
|
||||
val balance: String = "",
|
||||
val currency : Option[String],
|
||||
val label : Option[String],
|
||||
val nationalIdentifier : Option[String],
|
||||
val swift_bic : Option[String],
|
||||
val iban : Option[String],
|
||||
val number: Option[String],
|
||||
val bankName: Option[String],
|
||||
val bankPermalink : Option[String]
|
||||
){
|
||||
def toJson = {
|
||||
//TODO: Decide if unauthorized info (I guess that is represented by a 'none' option'? I can't really remember)
|
||||
// should just disappear from the json or if an empty string should be used.
|
||||
//I think we decided to use empty strings. What was the point of all the options again?
|
||||
("number" -> number.getOrElse("")) ~
|
||||
("owners" -> owners.flatten.map(owner =>
|
||||
("id" ->owner.id) ~
|
||||
("name" -> owner.name))) ~
|
||||
("type" -> accountType.getOrElse("")) ~
|
||||
("balance" ->
|
||||
("currency" -> currency.getOrElse("")) ~
|
||||
("amount" -> balance)) ~
|
||||
("IBAN" -> iban.getOrElse("")) ~
|
||||
("date_opened" -> "")
|
||||
}
|
||||
}
|
||||
|
||||
object ModeratedBankAccount {
|
||||
|
||||
def bankJson(holderName: String, isAlias : String, number: String,
|
||||
kind: String, bankIBAN: String, bankNatIdent: String,
|
||||
bankName: String) : JObject = {
|
||||
("holder" ->
|
||||
(
|
||||
("name" -> holderName) ~
|
||||
("alias"-> isAlias)
|
||||
))~
|
||||
("number" -> number) ~
|
||||
("kind" -> kind) ~
|
||||
("bank" ->
|
||||
("IBAN" -> bankIBAN) ~
|
||||
("national_identifier" -> bankNatIdent) ~
|
||||
("name" -> bankName))
|
||||
}
|
||||
|
||||
implicit def moderatedBankAccount2Json(mBankAccount: ModeratedBankAccount) : JObject = {
|
||||
val holderName = mBankAccount.owners match{
|
||||
case Some(ownersSet) => if(ownersSet.size!=0)
|
||||
ownersSet.toList(0).name
|
||||
else
|
||||
""
|
||||
case _ => ""
|
||||
}
|
||||
val isAlias = "no"
|
||||
val number = mBankAccount.number getOrElse ""
|
||||
val kind = mBankAccount.accountType getOrElse ""
|
||||
val bankIBAN = mBankAccount.iban.getOrElse("")
|
||||
val bankNatIdent = mBankAccount.nationalIdentifier getOrElse ""
|
||||
val bankName = mBankAccount.bankName getOrElse ""
|
||||
bankJson(holderName, isAlias, number, kind, bankIBAN, bankNatIdent, bankName)
|
||||
}
|
||||
}
|
||||
|
||||
class ModeratedOtherBankAccount(
|
||||
val id : String,
|
||||
val label : AccountName,
|
||||
val nationalIdentifier : Option[String],
|
||||
val swift_bic : Option[String],
|
||||
val iban : Option[String],
|
||||
val bankName : Option[String],
|
||||
val number : Option[String],
|
||||
val metadata : Option[ModeratedOtherBankAccountMetadata],
|
||||
val kind : Option[String]
|
||||
){
|
||||
|
||||
def isAlias : Boolean = label.aliasType match{
|
||||
case PublicAlias | PrivateAlias => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
object ModeratedOtherBankAccount {
|
||||
implicit def moderatedOtherBankAccount2Json(mOtherBank: ModeratedOtherBankAccount) : JObject = {
|
||||
val holderName = mOtherBank.label.display
|
||||
val isAlias = if(mOtherBank.isAlias) "yes" else "no"
|
||||
val number = mOtherBank.number getOrElse ""
|
||||
val kind = ""
|
||||
val bankIBAN = mOtherBank.iban.getOrElse("")
|
||||
val bankNatIdent = mOtherBank.nationalIdentifier getOrElse ""
|
||||
val bankName = mOtherBank.bankName getOrElse ""
|
||||
ModeratedBankAccount.bankJson(holderName, isAlias, number, kind, bankIBAN, bankNatIdent, bankName)
|
||||
}
|
||||
}
|
||||
|
||||
class ModeratedOtherBankAccountMetadata(
|
||||
val moreInfo : Option[String],
|
||||
val url : Option[String],
|
||||
val imageURL : Option[String],
|
||||
val openCorporatesURL : Option[String],
|
||||
val corporateLocation : Option[GeoTag],
|
||||
val physicalLocation : Option[GeoTag],
|
||||
val publicAlias : Option[String],
|
||||
val privateAlias : Option[String],
|
||||
val addMoreInfo : Option[(String) => Boolean],
|
||||
val addURL : Option[(String) => Boolean],
|
||||
val addImageURL : Option[(String) => Boolean],
|
||||
val addOpenCorporatesURL : Option[(String) => Boolean],
|
||||
val addCorporateLocation : Option[(String, Long, Date, Double, Double) => Boolean],
|
||||
val addPhysicalLocation : Option[(String, Long, Date, Double, Double) => Boolean],
|
||||
val addPublicAlias : Option[(String) => Boolean],
|
||||
val addPrivateAlias : Option[(String) => Boolean],
|
||||
val deleteCorporateLocation : Option[() => Boolean],
|
||||
val deletePhysicalLocation : Option[() => Boolean]
|
||||
)
|
||||
|
||||
object ModeratedOtherBankAccountMetadata {
|
||||
implicit def moderatedOtherBankAccountMetadata2Json(mOtherBankMeta: ModeratedOtherBankAccountMetadata) : JObject = {
|
||||
JObject(JField("blah", JString("test")) :: Nil)
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -33,9 +33,15 @@ package code.model
|
||||
import net.liftweb.mapper._
|
||||
import java.util.Date
|
||||
import scala.compat.Platform
|
||||
import code.model.dataAccess.OBPUser
|
||||
import net.liftweb.http.SHtml
|
||||
import net.liftweb.util.FieldError
|
||||
import net.liftweb.util.FieldIdentifier
|
||||
import net.liftweb.common.{Full,Failure,Box,Empty}
|
||||
import code.model.dataAccess.Admin
|
||||
import net.liftweb.util.Helpers
|
||||
import Helpers.now
|
||||
|
||||
object AppType extends Enumeration("web", "mobile")
|
||||
object AppType extends Enumeration("web", "mobile")
|
||||
{
|
||||
type AppType = Value
|
||||
val Web, Mobile = Value
|
||||
@ -47,35 +53,64 @@ object TokenType extends Enumeration("request", "access")
|
||||
val Request, Access = Value
|
||||
}
|
||||
|
||||
class Consumer extends LongKeyedMapper[Consumer]{
|
||||
class Consumer extends LongKeyedMapper[Consumer] with CreatedUpdated{
|
||||
def getSingleton = Consumer
|
||||
def primaryKeyField = id
|
||||
object id extends MappedLongIndex(this)
|
||||
object id extends MappedLongIndex(this)
|
||||
|
||||
def minLength3(field: MappedString[Consumer])( s : String) = {
|
||||
if(s.length() < 3) List(FieldError(field, {field.displayName + " must be at least 3 characters"}))
|
||||
else Nil
|
||||
}
|
||||
|
||||
object key extends MappedString(this, 250){
|
||||
override def dbIndexed_? = true
|
||||
}
|
||||
override def dbIndexed_? = true
|
||||
}
|
||||
object secret extends MappedString(this, 250)
|
||||
object isActive extends MappedBoolean(this)
|
||||
object name extends MappedString(this, 100){
|
||||
override def validations = minLength3(this) _ :: super.validations
|
||||
override def dbIndexed_? = true
|
||||
}
|
||||
object appType extends MappedEnum(this,AppType)
|
||||
object description extends MappedText(this)
|
||||
object developerEmail extends MappedString(this, 100)
|
||||
object insertDate extends MappedDateTime(this){
|
||||
override def defaultValue = new Date(Platform.currentTime)
|
||||
override def displayName = "App name:"
|
||||
}
|
||||
object updateDate extends MappedDateTime(this)
|
||||
object appType extends MappedEnum(this,AppType) {
|
||||
override def displayName = "App type:"
|
||||
}
|
||||
object description extends MappedText(this) {
|
||||
override def displayName = "Description:"
|
||||
}
|
||||
object developerEmail extends MappedEmail(this, 100) {
|
||||
def uniqueEmail(field: MappedEmail[Consumer])(s : String) = {
|
||||
Consumer.find(By(Consumer.developerEmail, s)) match {
|
||||
case Full(c) => List(FieldError(field, {"This email address is already registered."}))
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
override def displayName = "Email:"
|
||||
override def validations = uniqueEmail(this) _ :: super.validations
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object Consumer extends Consumer with LongKeyedMetaMapper[Consumer]{}
|
||||
object Consumer extends Consumer with LongKeyedMetaMapper[Consumer] with CRUDify[Long, Consumer]{
|
||||
//list all path : /admin/consumer/list
|
||||
override def calcPrefix = List("admin",_dbTableNameLC)
|
||||
|
||||
override def editMenuLocParams = List(Admin.testLogginIn)
|
||||
override def showAllMenuLocParams = List(Admin.testLogginIn)
|
||||
override def deleteMenuLocParams = List(Admin.testLogginIn)
|
||||
override def createMenuLocParams = List(Admin.testLogginIn)
|
||||
override def viewMenuLocParams = List(Admin.testLogginIn)
|
||||
|
||||
override def fieldOrder = List(name, appType, description, developerEmail)
|
||||
}
|
||||
|
||||
|
||||
class Nonce extends LongKeyedMapper[Nonce] {
|
||||
|
||||
|
||||
def getSingleton = Nonce
|
||||
def primaryKeyField = id
|
||||
object id extends MappedLongIndex(this)
|
||||
object id extends MappedLongIndex(this)
|
||||
object consumerkey extends MappedString(this, 250) //we store the consumer Key and we don't need to keep a reference to the token consumer as foreign key
|
||||
object tokenKey extends MappedString(this, 250){ //we store the token Key and we don't need to keep a reference to the token object as foreign key
|
||||
override def defaultValue = ""
|
||||
@ -87,24 +122,46 @@ class Nonce extends LongKeyedMapper[Nonce] {
|
||||
}
|
||||
}
|
||||
object value extends MappedString(this,250)
|
||||
|
||||
|
||||
}
|
||||
object Nonce extends Nonce with LongKeyedMetaMapper[Nonce]{}
|
||||
|
||||
|
||||
class Token extends LongKeyedMapper[Token]{
|
||||
def getSingleton = Token
|
||||
def getSingleton = Token
|
||||
def primaryKeyField = id
|
||||
object id extends MappedLongIndex(this) //TODO : auto increment
|
||||
object id extends MappedLongIndex(this)
|
||||
object tokenType extends MappedEnum(this, TokenType)
|
||||
object consumerId extends MappedLongForeignKey(this, Consumer)
|
||||
object userId extends MappedLongForeignKey(this, OBPUser)
|
||||
object userId extends MappedString(this,255)
|
||||
object key extends MappedString(this,250)
|
||||
object secret extends MappedString(this,250)
|
||||
object callbackURL extends MappedString(this,250)
|
||||
object verifier extends MappedString(this,250)
|
||||
object duration extends MappedLong(this)//expressed in milliseconds
|
||||
object duration extends MappedLong(this)//expressed in milliseconds
|
||||
object expirationDate extends MappedDateTime(this)
|
||||
object insertDate extends MappedDateTime(this)
|
||||
def user = User.findById(userId.get)
|
||||
def isValid : Boolean = expirationDate.is after now
|
||||
private def fiveRandomNumbers() : String = {
|
||||
def r() = Helpers.randomInt(9).toString //from zero to 9
|
||||
(1 to 5).map(x => r()).foldLeft("")(_ + _)
|
||||
}
|
||||
def gernerateVerifier : String =
|
||||
if (verifier.isEmpty)
|
||||
{
|
||||
val generatedVerifier = fiveRandomNumbers()
|
||||
verifier(generatedVerifier).save
|
||||
generatedVerifier
|
||||
}
|
||||
else
|
||||
verifier.is
|
||||
}
|
||||
object Token extends Token with LongKeyedMetaMapper[Token]{
|
||||
def gernerateVerifier(key : String) : Box[String] = {
|
||||
Token.find(key) match {
|
||||
case Full(tkn) => Full(tkn.gernerateVerifier)
|
||||
case _ => Failure("Token not found",Empty, Empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
object Token extends Token with LongKeyedMetaMapper[Token]{}
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -30,21 +30,37 @@ Berlin 13359, Germany
|
||||
|
||||
*/
|
||||
|
||||
package code.model.traits
|
||||
package code.model
|
||||
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
import code.model.dataAccess.LocalStorage
|
||||
import net.liftweb.common.Box
|
||||
|
||||
trait User {
|
||||
def id_ : String
|
||||
def provider : String
|
||||
def emailAddress : String
|
||||
def theFistName : String
|
||||
def theFirstName : String
|
||||
def theLastName : String
|
||||
def permittedViews(bankAccount: BankAccount) : Set[View]
|
||||
def hasMangementAccess(bankAccount: BankAccount) : Boolean
|
||||
def accountsWithMoreThanAnonAccess : Set[BankAccount]
|
||||
def toJson : JObject =
|
||||
override def toString = emailAddress
|
||||
|
||||
/**
|
||||
* @return the bank accounts where the user has at least access to a non public view (is_public==false)
|
||||
*/
|
||||
def nonPublicAccounts : Box[List[BankAccount]] = LocalStorage.getNonPublicBankAccounts(this)
|
||||
|
||||
def toJson : JObject =
|
||||
("id" -> id_) ~
|
||||
("provider" -> "sofi.openbankproject.com") ~
|
||||
("display_name" -> {theFistName + " " + theLastName})
|
||||
("display_name" -> {theFirstName + " " + theLastName})
|
||||
}
|
||||
|
||||
object User {
|
||||
def findById(id : String) : Box[User] =
|
||||
LocalStorage.getUser(id)
|
||||
def currentUser : Box[User] =
|
||||
LocalStorage.getCurrentUser
|
||||
}
|
||||
962
MavLift/src/main/scala/code/model/View.scala
Normal file
962
MavLift/src/main/scala/code/model/View.scala
Normal file
@ -0,0 +1,962 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
package code.model
|
||||
|
||||
import net.liftweb.http.SHtml
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
import net.liftweb.common.{Box, Empty, Full, Failure}
|
||||
import java.util.Date
|
||||
|
||||
|
||||
class AliasType
|
||||
class Alias extends AliasType
|
||||
object PublicAlias extends Alias
|
||||
object PrivateAlias extends Alias
|
||||
object NoAlias extends AliasType
|
||||
case class AccountName(display: String, aliasType: AliasType)
|
||||
case class Permission(
|
||||
user : User,
|
||||
views : List[View]
|
||||
)
|
||||
|
||||
trait View {
|
||||
|
||||
//e.g. "Public", "Authorities", "Our Network", etc.
|
||||
def id: Long
|
||||
def name: String
|
||||
def description : String
|
||||
def permalink : String
|
||||
def isPublic : Boolean
|
||||
|
||||
//the view settings
|
||||
def usePrivateAliasIfOneExists: Boolean
|
||||
def usePublicAliasIfOneExists: Boolean
|
||||
|
||||
//reading access
|
||||
|
||||
//transaction fields
|
||||
def canSeeTransactionThisBankAccount : Boolean
|
||||
def canSeeTransactionOtherBankAccount : Boolean
|
||||
def canSeeTransactionMetadata : Boolean
|
||||
def canSeeTransactionLabel: Boolean
|
||||
def canSeeTransactionAmount: Boolean
|
||||
def canSeeTransactionType: Boolean
|
||||
def canSeeTransactionCurrency: Boolean
|
||||
def canSeeTransactionStartDate: Boolean
|
||||
def canSeeTransactionFinishDate: Boolean
|
||||
def canSeeTransactionBalance: Boolean
|
||||
|
||||
//transaction metadata
|
||||
def canSeeComments: Boolean
|
||||
def canSeeOwnerComment: Boolean
|
||||
def canSeeTags : Boolean
|
||||
def canSeeImages : Boolean
|
||||
|
||||
//Bank account fields
|
||||
def canSeeBankAccountOwners : Boolean
|
||||
def canSeeBankAccountType : Boolean
|
||||
def canSeeBankAccountBalance : Boolean
|
||||
def canSeeBankAccountBalancePositiveOrNegative : Boolean
|
||||
def canSeeBankAccountCurrency : Boolean
|
||||
def canSeeBankAccountLabel : Boolean
|
||||
def canSeeBankAccountNationalIdentifier : Boolean
|
||||
def canSeeBankAccountSwift_bic : Boolean
|
||||
def canSeeBankAccountIban : Boolean
|
||||
def canSeeBankAccountNumber : Boolean
|
||||
def canSeeBankAccountBankName : Boolean
|
||||
def canSeeBankAccountBankPermalink : Boolean
|
||||
|
||||
//other bank account fields
|
||||
def canSeeOtherAccountNationalIdentifier : Boolean
|
||||
def canSeeSWIFT_BIC : Boolean
|
||||
def canSeeOtherAccountIBAN : Boolean
|
||||
def canSeeOtherAccountBankName : Boolean
|
||||
def canSeeOtherAccountNumber : Boolean
|
||||
def canSeeOtherAccountMetadata : Boolean
|
||||
def canSeeOtherAccountKind : Boolean
|
||||
|
||||
//other bank account meta data
|
||||
def canSeeMoreInfo: Boolean
|
||||
def canSeeUrl: Boolean
|
||||
def canSeeImageUrl: Boolean
|
||||
def canSeeOpenCorporatesUrl: Boolean
|
||||
def canSeeCorporateLocation : Boolean
|
||||
def canSeePhysicalLocation : Boolean
|
||||
def canSeePublicAlias : Boolean
|
||||
def canSeePrivateAlias : Boolean
|
||||
def canAddMoreInfo : Boolean
|
||||
def canAddURL : Boolean
|
||||
def canAddImageURL : Boolean
|
||||
def canAddOpenCorporatesUrl : Boolean
|
||||
def canAddCorporateLocation : Boolean
|
||||
def canAddPhysicalLocation : Boolean
|
||||
def canAddPublicAlias : Boolean
|
||||
def canAddPrivateAlias : Boolean
|
||||
def canDeleteCorporateLocation : Boolean
|
||||
def canDeletePhysicalLocation : Boolean
|
||||
|
||||
//writing access
|
||||
def canEditOwnerComment: Boolean
|
||||
def canAddComment : Boolean
|
||||
def canDeleteComment: Boolean
|
||||
def canAddTag : Boolean
|
||||
def canDeleteTag : Boolean
|
||||
def canAddImage : Boolean
|
||||
def canDeleteImage : Boolean
|
||||
def canAddWhereTag : Boolean
|
||||
def canSeeWhereTag : Boolean
|
||||
def canDeleteWhereTag : Boolean
|
||||
|
||||
// In the future we can add a method here to allow someone to show only transactions over a certain limit
|
||||
|
||||
def moderate(transaction: Transaction): ModeratedTransaction = {
|
||||
//transaction data
|
||||
val transactionId = transaction.id
|
||||
val transactionUUID = transaction.uuid
|
||||
val thisBankAccount = moderate(transaction.thisAccount)
|
||||
val otherBankAccount = moderate(transaction.otherAccount)
|
||||
|
||||
//transation metadata
|
||||
val transactionMetadata =
|
||||
if(canSeeTransactionMetadata)
|
||||
{
|
||||
val ownerComment = if (canSeeOwnerComment) Some(transaction.metadata.ownerComment) else None
|
||||
val comments =
|
||||
if (canSeeComments)
|
||||
Some(transaction.metadata.comments.filter(comment => comment.viewId==id))
|
||||
else None
|
||||
val addCommentFunc= if(canAddComment) Some(transaction.metadata.addComment) else None
|
||||
val deleteCommentFunc =
|
||||
if(canDeleteComment)
|
||||
Some(transaction.metadata.deleteComment)
|
||||
else
|
||||
None
|
||||
val addOwnerCommentFunc:Option[String=> Unit] = if (canEditOwnerComment) Some(transaction.metadata.addOwnerComment) else None
|
||||
val tags =
|
||||
if(canSeeTags)
|
||||
Some(transaction.metadata.tags.filter(_.viewId==id))
|
||||
else None
|
||||
val addTagFunc =
|
||||
if(canAddTag)
|
||||
Some(transaction.metadata.addTag)
|
||||
else
|
||||
None
|
||||
val deleteTagFunc =
|
||||
if(canDeleteTag)
|
||||
Some(transaction.metadata.deleteTag)
|
||||
else
|
||||
None
|
||||
val images =
|
||||
if(canSeeImages) Some(transaction.metadata.images.filter(_.viewId == id))
|
||||
else None
|
||||
|
||||
val addImageFunc =
|
||||
if(canAddImage) Some(transaction.metadata.addImage)
|
||||
else None
|
||||
|
||||
val deleteImageFunc =
|
||||
if(canDeleteImage) Some(transaction.metadata.deleteImage)
|
||||
else None
|
||||
|
||||
val whereTag =
|
||||
if(canSeeWhereTag)
|
||||
transaction.metadata.whereTags.find(tag => tag.viewId == id)
|
||||
else
|
||||
None
|
||||
|
||||
val addWhereTagFunc : Option[(String, Long, Date, Double, Double) => Boolean] =
|
||||
if(canAddWhereTag)
|
||||
Some(transaction.metadata.addWhereTag)
|
||||
else
|
||||
Empty
|
||||
|
||||
val deleteWhereTagFunc : Option[(Long) => Boolean] =
|
||||
if (canDeleteWhereTag)
|
||||
Some(transaction.metadata.deleteWhereTag)
|
||||
else
|
||||
Empty
|
||||
|
||||
|
||||
new Some(
|
||||
new ModeratedTransactionMetadata(
|
||||
ownerComment,
|
||||
addOwnerCommentFunc,
|
||||
comments,
|
||||
addCommentFunc,
|
||||
deleteCommentFunc,
|
||||
tags,
|
||||
addTagFunc,
|
||||
deleteTagFunc,
|
||||
images,
|
||||
addImageFunc,
|
||||
deleteImageFunc,
|
||||
whereTag,
|
||||
addWhereTagFunc,
|
||||
deleteWhereTagFunc
|
||||
))
|
||||
}
|
||||
else
|
||||
None
|
||||
|
||||
val transactionType =
|
||||
if (canSeeTransactionType) Some(transaction.transactionType)
|
||||
else None
|
||||
|
||||
val transactionAmount =
|
||||
if (canSeeTransactionAmount) Some(transaction.amount)
|
||||
else None
|
||||
|
||||
val transactionCurrency =
|
||||
if (canSeeTransactionCurrency) Some(transaction.currency)
|
||||
else None
|
||||
|
||||
val transactionLabel =
|
||||
if (canSeeTransactionLabel) transaction.label
|
||||
else None
|
||||
|
||||
val transactionStartDate =
|
||||
if (canSeeTransactionStartDate) Some(transaction.startDate)
|
||||
else None
|
||||
|
||||
val transactionFinishDate =
|
||||
if (canSeeTransactionFinishDate) Some(transaction.finishDate)
|
||||
else None
|
||||
|
||||
val transactionBalance =
|
||||
if (canSeeTransactionBalance) transaction.balance.toString()
|
||||
else ""
|
||||
|
||||
new ModeratedTransaction(transactionUUID, transactionId, thisBankAccount, otherBankAccount, transactionMetadata,
|
||||
transactionType, transactionAmount, transactionCurrency, transactionLabel, transactionStartDate,
|
||||
transactionFinishDate, transactionBalance)
|
||||
}
|
||||
|
||||
def moderate(bankAccount: BankAccount) : Option[ModeratedBankAccount] = {
|
||||
if(canSeeTransactionThisBankAccount)
|
||||
{
|
||||
val owners : Set[AccountOwner] = if(canSeeBankAccountOwners) bankAccount.owners else Set()
|
||||
val balance =
|
||||
if(canSeeBankAccountBalance){
|
||||
bankAccount.balance.toString
|
||||
} else if(canSeeBankAccountBalancePositiveOrNegative) {
|
||||
if(bankAccount.balance.toString.startsWith("-")) "-" else "+"
|
||||
} else ""
|
||||
val accountType = if(canSeeBankAccountType) Some(bankAccount.accountType) else None
|
||||
val currency = if(canSeeBankAccountCurrency) Some(bankAccount.currency) else None
|
||||
val label = if(canSeeBankAccountLabel) Some(bankAccount.label) else None
|
||||
val nationalIdentifier = if(canSeeBankAccountNationalIdentifier) Some(bankAccount.label) else None
|
||||
val swiftBic = if(canSeeBankAccountSwift_bic) bankAccount.swift_bic else None
|
||||
val iban = if(canSeeBankAccountIban) bankAccount.iban else None
|
||||
val number = if(canSeeBankAccountNumber) Some(bankAccount.number) else None
|
||||
val bankName = if(canSeeBankAccountBankName) Some(bankAccount.bankName) else None
|
||||
val bankPermalink = if(canSeeBankAccountBankPermalink) Some(bankAccount.bankPermalink) else None
|
||||
|
||||
Some(
|
||||
new ModeratedBankAccount(
|
||||
id = bankAccount.permalink,
|
||||
owners = Some(owners),
|
||||
accountType = accountType,
|
||||
balance = balance,
|
||||
currency = currency,
|
||||
label = label,
|
||||
nationalIdentifier = nationalIdentifier,
|
||||
swift_bic = swiftBic,
|
||||
iban = iban,
|
||||
number = number,
|
||||
bankName = bankName,
|
||||
bankPermalink = bankPermalink
|
||||
))
|
||||
}
|
||||
else
|
||||
None
|
||||
}
|
||||
|
||||
def moderate(otherBankAccount : OtherBankAccount) : Option[ModeratedOtherBankAccount] = {
|
||||
if (canSeeTransactionOtherBankAccount)
|
||||
{
|
||||
//other account data
|
||||
val otherAccountId = otherBankAccount.id
|
||||
val otherAccountLabel: AccountName = {
|
||||
val realName = otherBankAccount.label
|
||||
if (usePublicAliasIfOneExists) {
|
||||
|
||||
val publicAlias = otherBankAccount.metadata.publicAlias
|
||||
|
||||
if (! publicAlias.isEmpty ) AccountName(publicAlias, PublicAlias)
|
||||
else AccountName(realName, NoAlias)
|
||||
|
||||
} else if (usePrivateAliasIfOneExists) {
|
||||
|
||||
val privateAlias = otherBankAccount.metadata.privateAlias
|
||||
|
||||
if (! privateAlias.isEmpty) AccountName(privateAlias, PrivateAlias)
|
||||
else AccountName(realName, PrivateAlias)
|
||||
} else
|
||||
AccountName(realName, NoAlias)
|
||||
}
|
||||
val otherAccountNationalIdentifier = if (canSeeOtherAccountNationalIdentifier) Some(otherBankAccount.nationalIdentifier) else None
|
||||
val otherAccountSWIFT_BIC = if (canSeeSWIFT_BIC) otherBankAccount.swift_bic else None
|
||||
val otherAccountIBAN = if(canSeeOtherAccountIBAN) otherBankAccount.iban else None
|
||||
val otherAccountBankName = if(canSeeOtherAccountBankName) Some(otherBankAccount.bankName) else None
|
||||
val otherAccountNumber = if(canSeeOtherAccountNumber) Some(otherBankAccount.number) else None
|
||||
val otherAccountKind = if(canSeeOtherAccountKind) Some(otherBankAccount.kind) else None
|
||||
val otherAccountMetadata =
|
||||
if(canSeeOtherAccountMetadata)
|
||||
{
|
||||
//other bank account metadata
|
||||
val moreInfo =
|
||||
if (canSeeMoreInfo) Some(otherBankAccount.metadata.moreInfo)
|
||||
else None
|
||||
val url =
|
||||
if (canSeeUrl) Some(otherBankAccount.metadata.url)
|
||||
else None
|
||||
val imageUrl =
|
||||
if (canSeeImageUrl) Some(otherBankAccount.metadata.imageURL)
|
||||
else None
|
||||
val openCorporatesUrl =
|
||||
if (canSeeOpenCorporatesUrl) Some(otherBankAccount.metadata.openCorporatesURL)
|
||||
else None
|
||||
val corporateLocation : Option[GeoTag] =
|
||||
if(canSeeCorporateLocation)
|
||||
Some(otherBankAccount.metadata.corporateLocation)
|
||||
else
|
||||
None
|
||||
val physicalLocation : Option[GeoTag] =
|
||||
if(canSeePhysicalLocation)
|
||||
Some(otherBankAccount.metadata.physicalLocation)
|
||||
else
|
||||
None
|
||||
val addMoreInfo =
|
||||
if(canAddMoreInfo)
|
||||
Some(otherBankAccount.metadata.addMoreInfo)
|
||||
else
|
||||
None
|
||||
val addURL =
|
||||
if(canAddURL)
|
||||
Some(otherBankAccount.metadata.addURL)
|
||||
else
|
||||
None
|
||||
val addImageURL =
|
||||
if(canAddImageURL)
|
||||
Some(otherBankAccount.metadata.addImageURL)
|
||||
else
|
||||
None
|
||||
val addOpenCorporatesUrl =
|
||||
if(canAddOpenCorporatesUrl)
|
||||
Some(otherBankAccount.metadata.addOpenCorporatesURL)
|
||||
else
|
||||
None
|
||||
val addCorporateLocation =
|
||||
if(canAddCorporateLocation)
|
||||
Some(otherBankAccount.metadata.addCorporateLocation)
|
||||
else
|
||||
None
|
||||
val addPhysicalLocation =
|
||||
if(canAddPhysicalLocation)
|
||||
Some(otherBankAccount.metadata.addPhysicalLocation)
|
||||
else
|
||||
None
|
||||
val publicAlias =
|
||||
if(canSeePublicAlias)
|
||||
Some(otherBankAccount.metadata.publicAlias)
|
||||
else
|
||||
None
|
||||
val privateAlias =
|
||||
if(canSeePrivateAlias)
|
||||
Some(otherBankAccount.metadata.privateAlias)
|
||||
else
|
||||
None
|
||||
val addPublicAlias =
|
||||
if(canAddPublicAlias)
|
||||
Some(otherBankAccount.metadata.addPublicAlias)
|
||||
else
|
||||
None
|
||||
val addPrivateAlias =
|
||||
if(canAddPrivateAlias)
|
||||
Some(otherBankAccount.metadata.addPrivateAlias)
|
||||
else
|
||||
None
|
||||
val deleteCorporateLocation =
|
||||
if(canDeleteCorporateLocation)
|
||||
Some(otherBankAccount.metadata.deleteCorporateLocation)
|
||||
else
|
||||
None
|
||||
val deletePhysicalLocation=
|
||||
if(canDeletePhysicalLocation)
|
||||
Some(otherBankAccount.metadata.deletePhysicalLocation)
|
||||
else
|
||||
None
|
||||
|
||||
|
||||
Some(
|
||||
new ModeratedOtherBankAccountMetadata(
|
||||
moreInfo,
|
||||
url,
|
||||
imageUrl,
|
||||
openCorporatesUrl,
|
||||
corporateLocation,
|
||||
physicalLocation,
|
||||
publicAlias,
|
||||
privateAlias,
|
||||
addMoreInfo,
|
||||
addURL,
|
||||
addImageURL,
|
||||
addOpenCorporatesUrl,
|
||||
addCorporateLocation,
|
||||
addPhysicalLocation,
|
||||
addPublicAlias,
|
||||
addPrivateAlias,
|
||||
deleteCorporateLocation,
|
||||
deletePhysicalLocation
|
||||
))
|
||||
}
|
||||
else
|
||||
None
|
||||
|
||||
Some(
|
||||
new ModeratedOtherBankAccount(
|
||||
otherAccountId,
|
||||
otherAccountLabel,
|
||||
otherAccountNationalIdentifier,
|
||||
otherAccountSWIFT_BIC,
|
||||
otherAccountIBAN,
|
||||
otherAccountBankName,
|
||||
otherAccountNumber,
|
||||
otherAccountMetadata,
|
||||
otherAccountKind))
|
||||
}
|
||||
else
|
||||
None
|
||||
}
|
||||
|
||||
def toJson : JObject = {
|
||||
("name" -> name) ~
|
||||
("description" -> description)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//An implementation that has the least amount of permissions possible
|
||||
class BaseView extends View {
|
||||
def id = 1
|
||||
def name = "Restricted"
|
||||
def permalink = "restricted"
|
||||
def description = ""
|
||||
def isPublic = false
|
||||
|
||||
//the view settings
|
||||
def usePrivateAliasIfOneExists = true
|
||||
def usePublicAliasIfOneExists = true
|
||||
|
||||
//reading access
|
||||
|
||||
//transaction fields
|
||||
def canSeeTransactionThisBankAccount = false
|
||||
def canSeeTransactionOtherBankAccount = false
|
||||
def canSeeTransactionMetadata = false
|
||||
def canSeeTransactionLabel = false
|
||||
def canSeeTransactionAmount = false
|
||||
def canSeeTransactionType = false
|
||||
def canSeeTransactionCurrency = false
|
||||
def canSeeTransactionStartDate = false
|
||||
def canSeeTransactionFinishDate = false
|
||||
def canSeeTransactionBalance = false
|
||||
|
||||
//transaction metadata
|
||||
def canSeeComments = false
|
||||
def canSeeOwnerComment = false
|
||||
def canSeeTags = false
|
||||
def canSeeImages = false
|
||||
|
||||
//Bank account fields
|
||||
def canSeeBankAccountOwners = false
|
||||
def canSeeBankAccountType = false
|
||||
def canSeeBankAccountBalance = false
|
||||
def canSeeBankAccountBalancePositiveOrNegative = false
|
||||
def canSeeBankAccountCurrency = false
|
||||
def canSeeBankAccountLabel = false
|
||||
def canSeeBankAccountNationalIdentifier = false
|
||||
def canSeeBankAccountSwift_bic = false
|
||||
def canSeeBankAccountIban = false
|
||||
def canSeeBankAccountNumber = false
|
||||
def canSeeBankAccountBankName = false
|
||||
def canSeeBankAccountBankPermalink = false
|
||||
|
||||
//other bank account fields
|
||||
def canSeeOtherAccountNationalIdentifier = false
|
||||
def canSeeSWIFT_BIC = false
|
||||
def canSeeOtherAccountIBAN = false
|
||||
def canSeeOtherAccountBankName = false
|
||||
def canSeeOtherAccountNumber = false
|
||||
def canSeeOtherAccountMetadata = false
|
||||
def canSeeOtherAccountKind = false
|
||||
|
||||
//other bank account meta data
|
||||
def canSeeMoreInfo = false
|
||||
def canSeeUrl = false
|
||||
def canSeeImageUrl = false
|
||||
def canSeeOpenCorporatesUrl = false
|
||||
def canSeeCorporateLocation = false
|
||||
def canSeePhysicalLocation = false
|
||||
def canSeePublicAlias = false
|
||||
def canSeePrivateAlias = false
|
||||
|
||||
def canAddMoreInfo = false
|
||||
def canAddURL = false
|
||||
def canAddImageURL = false
|
||||
def canAddOpenCorporatesUrl = false
|
||||
def canAddCorporateLocation = false
|
||||
def canAddPhysicalLocation = false
|
||||
def canAddPublicAlias = false
|
||||
def canAddPrivateAlias = false
|
||||
def canDeleteCorporateLocation = false
|
||||
def canDeletePhysicalLocation = false
|
||||
|
||||
//writing access
|
||||
def canEditOwnerComment = false
|
||||
def canAddComment = false
|
||||
def canDeleteComment = false
|
||||
def canAddTag = false
|
||||
def canDeleteTag = false
|
||||
def canAddImage = false
|
||||
def canDeleteImage = false
|
||||
def canSeeWhereTag = false
|
||||
def canAddWhereTag = false
|
||||
def canDeleteWhereTag = false
|
||||
}
|
||||
|
||||
class FullView extends View {
|
||||
def id = 2
|
||||
def name = "Full"
|
||||
def permalink ="full"
|
||||
def description = ""
|
||||
def isPublic = false
|
||||
|
||||
//the view settings
|
||||
def usePrivateAliasIfOneExists = false
|
||||
def usePublicAliasIfOneExists = false
|
||||
|
||||
//reading access
|
||||
|
||||
//transaction fields
|
||||
def canSeeTransactionThisBankAccount = true
|
||||
def canSeeTransactionOtherBankAccount = true
|
||||
def canSeeTransactionMetadata = true
|
||||
def canSeeTransactionLabel = true
|
||||
def canSeeTransactionAmount = true
|
||||
def canSeeTransactionType = true
|
||||
def canSeeTransactionCurrency = true
|
||||
def canSeeTransactionStartDate = true
|
||||
def canSeeTransactionFinishDate = true
|
||||
def canSeeTransactionBalance = true
|
||||
|
||||
//transaction metadata
|
||||
def canSeeComments = true
|
||||
def canSeeOwnerComment = true
|
||||
def canSeeTags = true
|
||||
def canSeeImages = true
|
||||
|
||||
//Bank account fields
|
||||
def canSeeBankAccountOwners = true
|
||||
def canSeeBankAccountType = true
|
||||
def canSeeBankAccountBalance = true
|
||||
def canSeeBankAccountBalancePositiveOrNegative = true
|
||||
def canSeeBankAccountCurrency = true
|
||||
def canSeeBankAccountLabel = true
|
||||
def canSeeBankAccountNationalIdentifier = true
|
||||
def canSeeBankAccountSwift_bic = true
|
||||
def canSeeBankAccountIban = true
|
||||
def canSeeBankAccountNumber = true
|
||||
def canSeeBankAccountBankName = true
|
||||
def canSeeBankAccountBankPermalink = true
|
||||
|
||||
//other bank account fields
|
||||
def canSeeOtherAccountNationalIdentifier = true
|
||||
def canSeeSWIFT_BIC = true
|
||||
def canSeeOtherAccountIBAN = true
|
||||
def canSeeOtherAccountMetadata = true
|
||||
def canSeeOtherAccountBankName = true
|
||||
def canSeeOtherAccountNumber = true
|
||||
def canSeeOtherAccountKind = true
|
||||
|
||||
//other bank account meta data
|
||||
def canSeeMoreInfo = true
|
||||
def canSeeUrl = true
|
||||
def canSeeImageUrl = true
|
||||
def canSeeOpenCorporatesUrl = true
|
||||
def canSeeCorporateLocation = true
|
||||
def canSeePhysicalLocation = true
|
||||
def canSeePublicAlias = true
|
||||
def canSeePrivateAlias = true
|
||||
|
||||
def canAddMoreInfo = true
|
||||
def canAddURL = true
|
||||
def canAddImageURL = true
|
||||
def canAddOpenCorporatesUrl = true
|
||||
def canAddCorporateLocation = true
|
||||
def canAddPhysicalLocation = true
|
||||
def canAddPublicAlias = true
|
||||
def canAddPrivateAlias = true
|
||||
def canDeleteCorporateLocation = true
|
||||
def canDeletePhysicalLocation = true
|
||||
|
||||
//writing access
|
||||
def canEditOwnerComment = true
|
||||
def canAddComment = true
|
||||
def canDeleteComment = true
|
||||
def canAddTag = true
|
||||
def canDeleteTag = true
|
||||
def canAddImage = true
|
||||
def canDeleteImage = true
|
||||
def canSeeWhereTag = true
|
||||
def canAddWhereTag = true
|
||||
def canDeleteWhereTag = true
|
||||
}
|
||||
|
||||
|
||||
object View {
|
||||
//transform the url into a view
|
||||
//TODO : load the view from the Data base
|
||||
def fromUrl(viewNameURL: String): Box[View] =
|
||||
viewNameURL match {
|
||||
case "authorities" => Full(Authorities)
|
||||
case "board" => Full(Board)
|
||||
case "our-network" => Full(OurNetwork)
|
||||
case "team" => Full(Team)
|
||||
case "owner" => Full(Owner)
|
||||
case "public" | "anonymous" => Full(Public)
|
||||
case "management" => Full(Management)
|
||||
case _ => Failure("view " + viewNameURL + " not found", Empty, Empty)
|
||||
}
|
||||
|
||||
def linksJson(views: Set[View], accountPermalink: String, bankPermalink: String): JObject = {
|
||||
val viewsJson = views.map(view => {
|
||||
("rel" -> "account") ~
|
||||
("href" -> { "/" + bankPermalink + "/account/" + accountPermalink + "/" + view.permalink }) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> "Get information about one account")
|
||||
})
|
||||
|
||||
("links" -> viewsJson)
|
||||
}
|
||||
}
|
||||
|
||||
object Team extends FullView {
|
||||
override def id = 3
|
||||
override def name = "Team"
|
||||
override def permalink = "team"
|
||||
override def description = "A view for team members related to the account. E.g. for a company bank account -> employees/contractors"
|
||||
override def canEditOwnerComment= false
|
||||
|
||||
}
|
||||
object Board extends FullView {
|
||||
override def id = 4
|
||||
override def name = "Board"
|
||||
override def permalink = "board"
|
||||
override def description = "A view for board members of a company to view that company's account data."
|
||||
override def canEditOwnerComment= false
|
||||
}
|
||||
object Authorities extends FullView {
|
||||
override def id = 5
|
||||
override def name = "Authorities"
|
||||
override def permalink = "authorities"
|
||||
override def description = "A view for authorities such as tax officials to view an account's data"
|
||||
override def canEditOwnerComment= false
|
||||
}
|
||||
|
||||
object Public extends BaseView {
|
||||
//the actual class extends the BaseView but in fact it does not matters be cause we don't care about the values
|
||||
//of the canSeeMoreInfo, canSeeUrl,etc attributes and we implement a specific moderate method
|
||||
|
||||
/**
|
||||
* Current rules:
|
||||
*
|
||||
* If Public, and a public alias exists : Show the public alias
|
||||
* If Public, and no public alias exists : Show the real account holder
|
||||
* If our network, and a private alias exists : Show the private alias
|
||||
* If our network, and no private alias exists : Show the real account holder
|
||||
*/
|
||||
override def id = 6
|
||||
override def name = "Public"
|
||||
override def permalink = "public"
|
||||
override def description = "A view of the account accessible by anyone."
|
||||
override def isPublic = true
|
||||
|
||||
|
||||
//Bank account fields
|
||||
override def canSeeBankAccountOwners = true
|
||||
override def canSeeBankAccountType = true
|
||||
override def canSeeBankAccountBalancePositiveOrNegative = true
|
||||
override def canSeeBankAccountCurrency = true
|
||||
override def canSeeBankAccountLabel = true
|
||||
override def canSeeBankAccountNationalIdentifier = true
|
||||
override def canSeeBankAccountSwift_bic = true
|
||||
override def canSeeBankAccountIban = true
|
||||
override def canSeeBankAccountNumber = true
|
||||
override def canSeeBankAccountBankName = true
|
||||
|
||||
override def moderate(transaction: Transaction): ModeratedTransaction = {
|
||||
|
||||
val transactionId = transaction.id
|
||||
val transactionUUID = transaction.uuid
|
||||
val accountBalance = "" //not used when displaying transactions, but we might eventually need it. if so, we need a ref to
|
||||
//the bank account so we could do something like if(canSeeBankAccountBalance) bankAccount.balance else if
|
||||
// canSeeBankAccountBalancePositiveOrNegative {show + or -} else ""
|
||||
val thisBankAccount = moderate(transaction.thisAccount)
|
||||
val otherBankAccount = moderate(transaction.otherAccount)
|
||||
val transactionMetadata =
|
||||
Some(
|
||||
new ModeratedTransactionMetadata(
|
||||
Some(transaction.metadata.ownerComment),
|
||||
None,
|
||||
Some(transaction.metadata.comments.filter(comment => comment.viewId==id)),
|
||||
Some(transaction.metadata.addComment),
|
||||
Some(transaction.metadata.deleteComment),
|
||||
Some(transaction.metadata.tags.filter(_.viewId==id)),
|
||||
Some(transaction.metadata.addTag),
|
||||
Some(transaction.metadata.deleteTag),
|
||||
Some(transaction.metadata.images.filter(_.viewId==id)), //TODO: Better if image takes a view as a parameter?
|
||||
Some(transaction.metadata.addImage),
|
||||
Some(transaction.metadata.deleteImage),
|
||||
transaction.metadata.whereTags.find(tag => tag.viewId == id),
|
||||
Some(transaction.metadata.addWhereTag),
|
||||
Some(transaction.metadata.deleteWhereTag)
|
||||
))
|
||||
|
||||
val transactionType = Some(transaction.transactionType)
|
||||
val transactionAmount = Some(transaction.amount)
|
||||
val transactionCurrency = Some(transaction.currency)
|
||||
val transactionLabel = None
|
||||
val transactionStartDate = Some(transaction.startDate)
|
||||
val transactionFinishDate = Some(transaction.finishDate)
|
||||
val transactionBalance = if (transaction.balance.toString().startsWith("-")) "-" else "+"
|
||||
|
||||
new ModeratedTransaction(
|
||||
transactionUUID,
|
||||
transactionId,
|
||||
thisBankAccount,
|
||||
otherBankAccount,
|
||||
transactionMetadata,
|
||||
transactionType,
|
||||
transactionAmount,
|
||||
transactionCurrency,
|
||||
transactionLabel,
|
||||
transactionStartDate,
|
||||
transactionFinishDate,
|
||||
transactionBalance
|
||||
)
|
||||
}
|
||||
override def moderate(bankAccount: BankAccount) : Option[ModeratedBankAccount] = {
|
||||
Some(
|
||||
new ModeratedBankAccount(
|
||||
id = bankAccount.permalink,
|
||||
owners = Some(bankAccount.owners),
|
||||
accountType = Some(bankAccount.accountType),
|
||||
currency = Some(bankAccount.currency),
|
||||
label = Some(bankAccount.label),
|
||||
nationalIdentifier = None,
|
||||
swift_bic = None,
|
||||
iban = None,
|
||||
number = Some(bankAccount.number),
|
||||
bankName = Some(bankAccount.bankName),
|
||||
bankPermalink = Some(bankAccount.bankPermalink)
|
||||
)
|
||||
)
|
||||
}
|
||||
override def moderate(otherAccount : OtherBankAccount) : Option[ModeratedOtherBankAccount] = {
|
||||
val otherAccountLabel = {
|
||||
val publicAlias = otherAccount.metadata.publicAlias
|
||||
if(publicAlias.isEmpty)
|
||||
AccountName(otherAccount.label, NoAlias)
|
||||
else
|
||||
AccountName(publicAlias, PublicAlias)
|
||||
}
|
||||
val otherAccountMetadata = {
|
||||
def isPublicAlias = otherAccountLabel.aliasType match {
|
||||
case PublicAlias => true
|
||||
case _ => false
|
||||
}
|
||||
val moreInfo = if (isPublicAlias) None else Some(otherAccount.metadata.moreInfo)
|
||||
val url = if (isPublicAlias) None else Some(otherAccount.metadata.url)
|
||||
val imageUrl = if (isPublicAlias) None else Some(otherAccount.metadata.imageURL)
|
||||
val openCorporatesUrl = if (isPublicAlias) None else Some(otherAccount.metadata.openCorporatesURL)
|
||||
val corporateLocation = if (isPublicAlias) None else Some(otherAccount.metadata.corporateLocation)
|
||||
val physicalLocation = if (isPublicAlias) None else Some(otherAccount.metadata.physicalLocation)
|
||||
|
||||
Some(
|
||||
new ModeratedOtherBankAccountMetadata(
|
||||
moreInfo,
|
||||
url,
|
||||
imageUrl,
|
||||
openCorporatesUrl,
|
||||
corporateLocation,
|
||||
physicalLocation,
|
||||
Some(otherAccount.metadata.publicAlias),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(otherAccount.metadata.addCorporateLocation),
|
||||
Some(otherAccount.metadata.addPhysicalLocation),
|
||||
None,
|
||||
None,
|
||||
Some(otherAccount.metadata.deleteCorporateLocation),
|
||||
Some(otherAccount.metadata.deletePhysicalLocation)
|
||||
))
|
||||
}
|
||||
|
||||
Some(
|
||||
new ModeratedOtherBankAccount(
|
||||
otherAccount.id,
|
||||
otherAccountLabel,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
otherAccountMetadata,
|
||||
None))
|
||||
}
|
||||
}
|
||||
|
||||
object OurNetwork extends BaseView {
|
||||
override def id = 7
|
||||
override def name = "Our Network"
|
||||
override def permalink ="our-network"
|
||||
override def description = "A view for people related to the account in some way. E.g. for a company account this could include investors" +
|
||||
" or current/potential clients"
|
||||
override def moderate(transaction: Transaction): ModeratedTransaction = {
|
||||
val transactionId = transaction.id
|
||||
val transactionUUID = transaction.uuid
|
||||
val accountBalance = "" //not used when displaying transactions, but we might eventually need it. if so, we need a ref to
|
||||
//the bank account so we could do something like if(canSeeBankAccountBalance) bankAccount.balance else if
|
||||
// canSeeBankAccountBalancePositiveOrNegative {show + or -} else ""
|
||||
val thisBankAccount = moderate(transaction.thisAccount)
|
||||
val otherBankAccount = moderate(transaction.otherAccount)
|
||||
val transactionMetadata =
|
||||
Some(
|
||||
new ModeratedTransactionMetadata(
|
||||
Some(transaction.metadata.ownerComment),
|
||||
None,
|
||||
Some(transaction.metadata.comments.filter(comment => comment.viewId==id)),
|
||||
Some(transaction.metadata.addComment),
|
||||
Some(transaction.metadata.deleteComment),
|
||||
Some(transaction.metadata.tags.filter(_.viewId==id)),
|
||||
Some(transaction.metadata.addTag),
|
||||
Some(transaction.metadata.deleteTag),
|
||||
Some(transaction.metadata.images.filter(_.viewId==id)), //TODO: Better if image takes a view as a parameter?
|
||||
Some(transaction.metadata.addImage),
|
||||
Some(transaction.metadata.deleteImage),
|
||||
transaction.metadata.whereTags.find(tag => tag.viewId == id),
|
||||
Some(transaction.metadata.addWhereTag),
|
||||
Some(transaction.metadata.deleteWhereTag)
|
||||
))
|
||||
val transactionType = Some(transaction.transactionType)
|
||||
val transactionAmount = Some(transaction.amount)
|
||||
val transactionCurrency = Some(transaction.currency)
|
||||
val transactionLabel = transaction.label
|
||||
val transactionStartDate = Some(transaction.startDate)
|
||||
val transactionFinishDate = Some(transaction.finishDate)
|
||||
val transactionBalance = transaction.balance.toString()
|
||||
|
||||
new ModeratedTransaction(transactionUUID, transactionId, thisBankAccount, otherBankAccount, transactionMetadata,
|
||||
transactionType, transactionAmount, transactionCurrency, transactionLabel, transactionStartDate,
|
||||
transactionFinishDate, transactionBalance)
|
||||
}
|
||||
override def moderate(bankAccount: BankAccount) : Option[ModeratedBankAccount] = {
|
||||
Some(
|
||||
new ModeratedBankAccount(
|
||||
id = bankAccount.permalink,
|
||||
owners = Some(bankAccount.owners),
|
||||
accountType = Some(bankAccount.accountType),
|
||||
currency = Some(bankAccount.currency),
|
||||
label = Some(bankAccount.label),
|
||||
nationalIdentifier = None,
|
||||
swift_bic = None,
|
||||
iban = None,
|
||||
number = Some(bankAccount.number),
|
||||
bankName = Some(bankAccount.bankName),
|
||||
bankPermalink = Some(bankAccount.bankPermalink)
|
||||
)
|
||||
)
|
||||
}
|
||||
override def moderate(otherAccount : OtherBankAccount) : Option[ModeratedOtherBankAccount] = {
|
||||
val otherAccountLabel = {
|
||||
val privateAlias = otherAccount.metadata.privateAlias
|
||||
if(privateAlias.isEmpty)
|
||||
AccountName(otherAccount.label, NoAlias)
|
||||
else
|
||||
AccountName(privateAlias, PrivateAlias)
|
||||
}
|
||||
val otherAccountMetadata =
|
||||
Some(
|
||||
new ModeratedOtherBankAccountMetadata(
|
||||
Some(otherAccount.metadata.moreInfo),
|
||||
Some(otherAccount.metadata.url),
|
||||
Some(otherAccount.metadata.imageURL),
|
||||
Some(otherAccount.metadata.openCorporatesURL),
|
||||
Some(otherAccount.metadata.corporateLocation),
|
||||
Some(otherAccount.metadata.physicalLocation),
|
||||
Some(otherAccount.metadata.publicAlias),
|
||||
Some(otherAccount.metadata.privateAlias),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(otherAccount.metadata.addCorporateLocation),
|
||||
Some(otherAccount.metadata.addPhysicalLocation),
|
||||
Some(otherAccount.metadata.addPublicAlias),
|
||||
Some(otherAccount.metadata.addPrivateAlias),
|
||||
Some(otherAccount.metadata.deleteCorporateLocation),
|
||||
Some(otherAccount.metadata.deletePhysicalLocation)
|
||||
))
|
||||
|
||||
Some(new ModeratedOtherBankAccount(otherAccount.id,otherAccountLabel,None,None,None,
|
||||
None, None, otherAccountMetadata, None))
|
||||
}
|
||||
}
|
||||
|
||||
object Owner extends FullView {
|
||||
override def id = 8
|
||||
override def name="Owner"
|
||||
override def permalink = "owner"
|
||||
}
|
||||
|
||||
object Management extends FullView {
|
||||
override def id = 9
|
||||
override def name="Management"
|
||||
override def permalink = "management"
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,21 +15,21 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
package code.model.dataAccess
|
||||
|
||||
import com.mongodb.QueryBuilder
|
||||
@ -37,20 +37,20 @@ import net.liftweb.mongodb.JsonObjectMeta
|
||||
import net.liftweb.mongodb.JsonObject
|
||||
import net.liftweb.mongodb.record.MongoMetaRecord
|
||||
import net.liftweb.mongodb.record.field.ObjectIdPk
|
||||
import net.liftweb.mongodb.record.field.ObjectIdRefListField
|
||||
import net.liftweb.mongodb.record.MongoRecord
|
||||
import net.liftweb.mongodb.record.field.{BsonRecordField , ObjectIdRefField}
|
||||
import net.liftweb.mongodb.record.field.ObjectIdRefField
|
||||
import net.liftweb.mongodb.record.field.MongoJsonObjectListField
|
||||
import net.liftweb.mongodb.record.field.DateField
|
||||
import net.liftweb.common.{ Box, Empty, Full }
|
||||
import net.liftweb.mongodb.record.field.BsonRecordListField
|
||||
import net.liftweb.common.{ Box, Empty, Full, Failure }
|
||||
import net.liftweb.mongodb.record.field.BsonRecordField
|
||||
import net.liftweb.mongodb.record.{ BsonRecord, BsonMetaRecord }
|
||||
import net.liftweb.record.field.{ StringField, BooleanField }
|
||||
import net.liftweb.record.field.{ StringField, BooleanField, DecimalField }
|
||||
import net.liftweb.mongodb.{Limit, Skip}
|
||||
import code.model.dataAccess.OBPEnvelope._
|
||||
import code.model.traits.ModeratedTransaction
|
||||
import code.model.traits.BankAccount
|
||||
import code.model.implementedTraits.{ BankAccountImpl, AccountOwnerImpl }
|
||||
import code.model.{ModeratedTransaction, AccountOwner, BankAccount}
|
||||
import net.liftweb.mongodb.BsonDSL._
|
||||
import java.util.Date
|
||||
import OBPEnvelope._
|
||||
|
||||
|
||||
/**
|
||||
@ -63,6 +63,7 @@ import net.liftweb.mongodb.BsonDSL._
|
||||
class Account extends MongoRecord[Account] with ObjectIdPk[Account] {
|
||||
def meta = Account
|
||||
|
||||
object balance extends DecimalField(this, 0)
|
||||
object anonAccess extends BooleanField(this, false)
|
||||
object holder extends StringField(this, 255)
|
||||
object number extends StringField(this, 255)
|
||||
@ -74,36 +75,36 @@ class Account extends MongoRecord[Account] with ObjectIdPk[Account] {
|
||||
object currency extends StringField(this, 255)
|
||||
object iban extends StringField(this, 255)
|
||||
object lastUpdate extends DateField(this)
|
||||
object otherAccounts extends BsonRecordListField(this, OtherAccount)
|
||||
|
||||
object otherAccounts extends ObjectIdRefListField(this, OtherAccount)
|
||||
|
||||
def bankName : String = bankID.obj match {
|
||||
case Full(bank) => bank.name.get
|
||||
case _ => ""
|
||||
case _ => ""
|
||||
}
|
||||
def bankPermalink : String = bankID.obj match {
|
||||
case Full(bank) => bank.permalink.get
|
||||
case _ => ""
|
||||
case _ => ""
|
||||
}
|
||||
|
||||
|
||||
def transactionsForAccount = QueryBuilder.start("obp_transaction.this_account.number").is(number.get).
|
||||
put("obp_transaction.this_account.kind").is(kind.get).
|
||||
put("obp_transaction.this_account.holder").is(holder.get).
|
||||
put("obp_transaction.this_account.bank.name").is(bankName)
|
||||
|
||||
//find all the envelopes related to this account
|
||||
//find all the envelopes related to this account
|
||||
def allEnvelopes: List[OBPEnvelope] = OBPEnvelope.findAll(transactionsForAccount.get)
|
||||
|
||||
def envelopes(queryParams: OBPQueryParam*): List[OBPEnvelope] = {
|
||||
val DefaultSortField = "obp_transaction.details.completed"
|
||||
//This is ugly with the casts but it is a similar approach to mongo's .findAll implementation
|
||||
val limit = queryParams.find(q => q.isInstanceOf[OBPLimit]).asInstanceOf[Option[OBPLimit]].map(x => x.value).getOrElse(50)
|
||||
val offset = queryParams.find(q => q.isInstanceOf[OBPOffset]).asInstanceOf[Option[OBPOffset]].map(x => x.value).getOrElse(0)
|
||||
val orderingParams = queryParams.find(q => q.isInstanceOf[OBPOrdering]).
|
||||
asInstanceOf[Option[OBPOrdering]].map(x => x).
|
||||
getOrElse(OBPOrdering(Some(DefaultSortField), OBPDescending))
|
||||
|
||||
val fromDate = queryParams.find(q => q.isInstanceOf[OBPFromDate]).asInstanceOf[Option[OBPFromDate]]
|
||||
val toDate = queryParams.find(q => q.isInstanceOf[OBPToDate]).asInstanceOf[Option[OBPToDate]]
|
||||
|
||||
|
||||
val limit = queryParams.collect { case OBPLimit(value) => value }.headOption.getOrElse(50)
|
||||
val offset = queryParams.collect { case OBPOffset(value) => value }.headOption.getOrElse(0)
|
||||
val orderingParams = queryParams.collect { case param: OBPOrdering => param}.headOption
|
||||
.getOrElse(OBPOrdering(Some(DefaultSortField), OBPDescending))
|
||||
|
||||
val fromDate = queryParams.collect { case param: OBPFromDate => param }.headOption
|
||||
val toDate = queryParams.collect { case param: OBPFromDate => param }.headOption
|
||||
|
||||
val mongoParams = {
|
||||
val start = transactionsForAccount
|
||||
val start2 = if(fromDate.isDefined) start.put("obp_transaction.details.completed").greaterThanEquals(fromDate.get.value)
|
||||
@ -112,9 +113,9 @@ class Account extends MongoRecord[Account] with ObjectIdPk[Account] {
|
||||
else start2
|
||||
end.get
|
||||
}
|
||||
|
||||
|
||||
val ordering = QueryBuilder.start(orderingParams.field.getOrElse(DefaultSortField)).is(orderingParams.order.orderValue).get
|
||||
|
||||
|
||||
OBPEnvelope.findAll(mongoParams, ordering, Limit(limit), Skip(offset))
|
||||
}
|
||||
}
|
||||
@ -122,20 +123,32 @@ class Account extends MongoRecord[Account] with ObjectIdPk[Account] {
|
||||
object Account extends Account with MongoMetaRecord[Account] {
|
||||
def toBankAccount(account: Account): BankAccount = {
|
||||
val iban = if (account.iban.toString.isEmpty) None else Some(account.iban.toString)
|
||||
var bankAccount = new BankAccountImpl(account.id.toString, Set(), account.kind.toString, account.currency.toString, account.label.toString,
|
||||
"", None, iban, account.anonAccess.get, account.number.get, account.bankName, account.bankPermalink, account.permalink.get)
|
||||
val owners = Set(new AccountOwnerImpl("", account.holder.toString, Set(bankAccount)))
|
||||
bankAccount.owners = Set(new AccountOwnerImpl("", account.holder.toString, Set(bankAccount)))
|
||||
|
||||
val bankAccount =
|
||||
new BankAccount(
|
||||
account.id.toString,
|
||||
Set(new AccountOwner("", account.holder.toString)),
|
||||
account.kind.toString,
|
||||
account.balance.get,
|
||||
account.currency.toString,
|
||||
account.name.get,
|
||||
account.label.toString,
|
||||
"",
|
||||
None,
|
||||
iban,
|
||||
account.anonAccess.get,
|
||||
account.number.get,
|
||||
account.bankName,
|
||||
account.bankPermalink,
|
||||
account.permalink.get
|
||||
)
|
||||
bankAccount
|
||||
}
|
||||
}
|
||||
|
||||
class OtherAccount private () extends BsonRecord[OtherAccount] {
|
||||
class OtherAccount private() extends MongoRecord[OtherAccount] with ObjectIdPk[OtherAccount] {
|
||||
def meta = OtherAccount
|
||||
|
||||
object holder extends StringField(this, 200)
|
||||
|
||||
object publicAlias extends StringField(this, 100)
|
||||
object privateAlias extends StringField(this, 100)
|
||||
object moreInfo extends StringField(this, 100)
|
||||
@ -144,26 +157,66 @@ class OtherAccount private () extends BsonRecord[OtherAccount] {
|
||||
object openCorporatesUrl extends StringField(this, 100) {
|
||||
override def optional_? = true
|
||||
}
|
||||
object corporateLocation extends BsonRecordField(this, OBPGeoTag)
|
||||
object physicalLocation extends BsonRecordField(this, OBPGeoTag)
|
||||
|
||||
def addCorporateLocation(userId: String, viewId : Long, datePosted : Date, longitude : Double, latitude : Double) : Boolean = {
|
||||
val newTag = OBPGeoTag.createRecord.
|
||||
userId(userId).
|
||||
viewID(viewId).
|
||||
date(datePosted).
|
||||
geoLongitude(longitude).
|
||||
geoLatitude(latitude)
|
||||
corporateLocation(newTag).save
|
||||
true
|
||||
}
|
||||
|
||||
def deleteCorporateLocation : Boolean = {
|
||||
corporateLocation.clear
|
||||
this.save
|
||||
true
|
||||
}
|
||||
|
||||
def addPhysicalLocation(userId: String, viewId : Long, datePosted : Date, longitude : Double, latitude : Double) : Boolean = {
|
||||
val newTag = OBPGeoTag.createRecord.
|
||||
userId(userId).
|
||||
viewID(viewId).
|
||||
date(datePosted).
|
||||
geoLongitude(longitude).
|
||||
geoLatitude(latitude)
|
||||
physicalLocation(newTag).save
|
||||
true
|
||||
}
|
||||
|
||||
def deletePhysicalLocation : Boolean = {
|
||||
physicalLocation.clear
|
||||
this.save
|
||||
true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object OtherAccount extends OtherAccount with BsonMetaRecord[OtherAccount]
|
||||
object OtherAccount extends OtherAccount with MongoMetaRecord[OtherAccount]
|
||||
|
||||
class HostedBank extends MongoRecord[HostedBank] with ObjectIdPk[HostedBank]{
|
||||
def meta = HostedBank
|
||||
|
||||
object name extends StringField(this, 255)
|
||||
object alias extends StringField(this, 255)
|
||||
object logo extends StringField(this, 255)
|
||||
object logoURL extends StringField(this, 255)
|
||||
object website extends StringField(this, 255)
|
||||
object email extends StringField(this, 255)
|
||||
object permalink extends StringField(this, 255)
|
||||
object SWIFT_BIC extends StringField(this, 255)
|
||||
object national_identifier extends StringField(this, 255)
|
||||
|
||||
def getAccount(bankAccountPermalink : String) : Box[Account] =
|
||||
Account.find(("permalink" -> bankAccountPermalink) ~ ("bankID" -> id.is))
|
||||
|
||||
def isAccount(bankAccountPermalink : String) : Boolean =
|
||||
def getAccount(bankAccountPermalink : String) : Box[Account] =
|
||||
Account.find(("permalink" -> bankAccountPermalink) ~ ("bankID" -> id.is)) match {
|
||||
case Full(account) => Full(account)
|
||||
case _ => Failure("account " + bankAccountPermalink +" not found in bank " + permalink, Empty, Empty)
|
||||
}
|
||||
|
||||
def isAccount(bankAccountPermalink : String) : Boolean =
|
||||
Account.count(("permalink" -> bankAccountPermalink) ~ ("bankID" -> id.is)) == 1
|
||||
|
||||
}
|
||||
|
||||
108
MavLift/src/main/scala/code/model/dataAccess/Admin.scala
Normal file
108
MavLift/src/main/scala/code/model/dataAccess/Admin.scala
Normal file
@ -0,0 +1,108 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.model.dataAccess
|
||||
|
||||
import net.liftweb.mapper._
|
||||
import net.liftweb.util._
|
||||
import net.liftweb.common._
|
||||
import scala.xml.NodeSeq
|
||||
import net.liftweb.sitemap.Loc.LocGroup
|
||||
import net.liftweb.http.{S,SessionVar,Templates}
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.http.{SHtml,S}
|
||||
import net.liftweb.util.Helpers._
|
||||
import org.bson.types.ObjectId
|
||||
import com.mongodb.DBObject
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
|
||||
|
||||
/**
|
||||
* This class to handel the administration of the API, like the API OAuth keys.
|
||||
*/
|
||||
class Admin extends MegaProtoUser[Admin] {
|
||||
def getSingleton = Admin // what's the "meta" server
|
||||
}
|
||||
|
||||
object Admin extends Admin with MetaMegaProtoUser[Admin]{
|
||||
|
||||
override def dbTableName = "admins" // define the DB table name
|
||||
|
||||
override def screenWrap = Full(<lift:surround with="default" at="content">
|
||||
<lift:bind /></lift:surround>)
|
||||
// define the order fields will appear in forms and output
|
||||
override def fieldOrder = List(id, firstName, lastName, email,
|
||||
locale, timezone, password)
|
||||
|
||||
// comment this line out to require email validations
|
||||
override def skipEmailValidation = true
|
||||
|
||||
//Keep track of the referer on login
|
||||
object loginReferer extends SessionVar("/")
|
||||
|
||||
//This is where the user gets redirected to after login
|
||||
override def homePage = {
|
||||
val ret = loginReferer.is
|
||||
loginReferer.remove()
|
||||
ret
|
||||
}
|
||||
|
||||
override def loginXhtml = {
|
||||
import net.liftweb.http.TemplateFinder
|
||||
import net.liftweb.http.js.JsCmds.Noop
|
||||
val loginXml = Templates(List("templates-hidden","_Adminlogin")).map({
|
||||
"form [action]" #> {S.uri} &
|
||||
"#loginText * " #> {S.??("log.in")} &
|
||||
"#emailAddressText * " #> {S.??("email.address")} &
|
||||
"#passwordText * " #> {S.??("password")} &
|
||||
"#recoverPasswordLink * " #> {
|
||||
"a [href]" #> {lostPasswordPath.mkString("/", "/", "")} &
|
||||
"a *" #> {S.??("recover.password")}
|
||||
}
|
||||
})
|
||||
SHtml.span(loginXml getOrElse NodeSeq.Empty,Noop)
|
||||
}
|
||||
|
||||
//disable the sign up page
|
||||
override def createUserMenuLoc = Empty
|
||||
|
||||
// the admin edit page
|
||||
override def editUserMenuLoc = Empty
|
||||
|
||||
//Set the login referer
|
||||
override def login = {
|
||||
for(
|
||||
r <- S.referer
|
||||
if loginReferer.is.equals("/")
|
||||
) loginReferer.set(r)
|
||||
super.login
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -31,59 +31,77 @@ Berlin 13359, Germany
|
||||
*/
|
||||
package code.model.dataAccess
|
||||
|
||||
import code.model.traits._
|
||||
import code.model.implementedTraits._
|
||||
import net.liftweb.common.{ Box, Empty, Full }
|
||||
import code.model._
|
||||
import net.liftweb.common.{ Box, Empty, Full, Failure }
|
||||
import net.liftweb.util.Helpers.tryo
|
||||
import net.liftweb.mongodb.BsonDSL._
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.common.Loggable
|
||||
import code.model.dataAccess.OBPEnvelope.OBPQueryParam
|
||||
import net.liftweb.mapper.By
|
||||
import net.liftweb.mapper.{By,IHaveValidatedThisSQL}
|
||||
import net.liftweb.mongodb.MongoDB
|
||||
import com.mongodb.BasicDBList
|
||||
import java.util.ArrayList
|
||||
import org.bson.types.ObjectId
|
||||
import net.liftweb.mapper.BySql
|
||||
import net.liftweb.db.DB
|
||||
|
||||
object LocalStorage extends MongoDBLocalStorage
|
||||
|
||||
trait LocalStorage extends Loggable {
|
||||
def getModeratedTransactions(permalink: String, bankPermalink: String)
|
||||
(moderate: Transaction => ModeratedTransaction): List[ModeratedTransaction] = {
|
||||
val rawTransactions = getTransactions(permalink, bankPermalink) getOrElse Nil
|
||||
rawTransactions.map(moderate)
|
||||
}
|
||||
|
||||
def getModeratedTransactions(permalink: String, bankPermalink: String, queryParams: OBPQueryParam*)
|
||||
(moderate: Transaction => ModeratedTransaction): List[ModeratedTransaction] = {
|
||||
val rawTransactions = getTransactions(permalink, bankPermalink, queryParams: _*) getOrElse Nil
|
||||
rawTransactions.map(moderate)
|
||||
}
|
||||
|
||||
def getTransactions(permalink: String, bankPermalink: String, queryParams: OBPQueryParam*) : Box[List[Transaction]] = {
|
||||
val envelopesForAccount = (acc: Account) => acc.envelopes(queryParams: _*)
|
||||
getTransactions(permalink, bankPermalink, envelopesForAccount)
|
||||
}
|
||||
|
||||
def getTransactions(permalink: String, bankPermalink: String): Box[List[Transaction]] = {
|
||||
val envelopesForAccount = (acc: Account) => acc.allEnvelopes
|
||||
getTransactions(permalink, bankPermalink, envelopesForAccount)
|
||||
}
|
||||
|
||||
def getTransactions(bank: String, account: String, envelopesForAccount: Account => List[OBPEnvelope]): Box[List[Transaction]]
|
||||
|
||||
def getBank(name: String): Box[Bank]
|
||||
|
||||
def getBankAccounts(bank: Bank): Set[BankAccount]
|
||||
|
||||
def allBanks : List[Bank]
|
||||
|
||||
//TODO: remove after the split because useless
|
||||
def getAccount(bankpermalink: String, account: String): Box[Account]
|
||||
|
||||
def getBankAccount(bankId : String, bankAccountId : String) : Box[BankAccount]
|
||||
|
||||
def getAllPublicAccounts() : List[BankAccount]
|
||||
|
||||
def getPublicBankAccounts(bank : Bank) : Box[List[BankAccount]]
|
||||
|
||||
def getNonPublicBankAccounts(user : User) : Box[List[BankAccount]]
|
||||
|
||||
def getNonPublicBankAccounts(user : User, bankID : String) : Box[List[BankAccount]]
|
||||
|
||||
//TODO: remove after the split because useless
|
||||
def correctBankAndAccount(bank: String, account: String): Boolean
|
||||
|
||||
def getAccount(bankpermalink: String, account: String): Box[Account]
|
||||
def getTransaction(id : String, bankPermalink : String, accountPermalink : String) : Box[Transaction]
|
||||
def getModeratedOtherBankAccount(accountID : String, otherAccountID : String)
|
||||
(moderate: OtherBankAccount => Option[ModeratedOtherBankAccount]) : Box[ModeratedOtherBankAccount]
|
||||
|
||||
def getModeratedOtherBankAccounts(accountID : String)
|
||||
(moderate: OtherBankAccount => Option[ModeratedOtherBankAccount]): Box[List[ModeratedOtherBankAccount]]
|
||||
|
||||
def getModeratedTransactions(permalink: String, bankPermalink: String, queryParams: OBPQueryParam*)
|
||||
(moderate: Transaction => ModeratedTransaction): Box[List[ModeratedTransaction]]
|
||||
|
||||
def getUser(id : String) : Box[User]
|
||||
|
||||
def getCurrentUser : Box[User]
|
||||
|
||||
def permissions(account : BankAccount) : Box[List[Permission]]
|
||||
|
||||
def addPermission(bankAccountId : String, view : View, user : User) : Box[Boolean]
|
||||
|
||||
def addPermissions(bankAccountId : String, views : List[View], user : User) : Box[Boolean]
|
||||
|
||||
def revokePermission(bankAccountId : String, view : View, user : User) : Box[Boolean]
|
||||
|
||||
def revokeAllPermission(bankAccountId : String, user : User) : Box[Boolean]
|
||||
|
||||
def views(bankAccountID : String) : Box[List[View]]
|
||||
|
||||
}
|
||||
|
||||
class MongoDBLocalStorage extends LocalStorage {
|
||||
private def createTransaction(env: OBPEnvelope, theAccount: Account): Transaction =
|
||||
{
|
||||
|
||||
private val availableViews = List(Team, Board, Authorities, Public, OurNetwork, Owner, Management)
|
||||
|
||||
private def createTransaction(env: OBPEnvelope, theAccount: Account): Transaction = {
|
||||
import net.liftweb.json.JsonDSL._
|
||||
val transaction: OBPTransaction = env.obp_transaction.get
|
||||
val thisAccount = transaction.this_account
|
||||
@ -91,94 +109,563 @@ class MongoDBLocalStorage extends LocalStorage {
|
||||
val otherUnmediatedHolder = otherAccount_.holder.get
|
||||
|
||||
val thisBankAccount = Account.toBankAccount(theAccount)
|
||||
|
||||
val oAccs = theAccount.otherAccounts.get
|
||||
val oAccOpt = oAccs.find(o => {
|
||||
otherUnmediatedHolder.equals(o.holder.get)
|
||||
})
|
||||
|
||||
val oAcc = oAccOpt getOrElse {
|
||||
val oAcc = theAccount.otherAccounts.objs.find(o => {
|
||||
otherUnmediatedHolder.equals(o.holder.get)
|
||||
}).getOrElse {
|
||||
OtherAccount.createRecord
|
||||
}
|
||||
|
||||
val id = env.id.is.toString()
|
||||
val oSwiftBic = None
|
||||
val otherAccount = new OtherBankAccountImpl(
|
||||
id_ = "",
|
||||
label_ = otherAccount_.holder.get,
|
||||
nationalIdentifier_ = otherAccount_.bank.get.national_identifier.get,
|
||||
swift_bic_ = None, //TODO: need to add this to the json/model
|
||||
iban_ = Some(otherAccount_.bank.get.IBAN.get),
|
||||
number_ = otherAccount_.number.get,
|
||||
bankName_ = "", //TODO: need to add this to the json/model
|
||||
metadata_ = new OtherBankAccountMetadataImpl(oAcc.publicAlias.get, oAcc.privateAlias.get, oAcc.moreInfo.get,
|
||||
oAcc.url.get, oAcc.imageUrl.get, oAcc.openCorporatesUrl.get))
|
||||
val metadata = new TransactionMetadataImpl(env.narrative.get, env.obp_comments.objs,
|
||||
(text => env.narrative(text).save), env.addComment _)
|
||||
val transactionType = env.obp_transaction.get.details.get.type_en.get
|
||||
val amount = env.obp_transaction.get.details.get.value.get.amount.get
|
||||
val currency = env.obp_transaction.get.details.get.value.get.currency.get
|
||||
val label = None
|
||||
val startDate = env.obp_transaction.get.details.get.posted.get
|
||||
val finishDate = env.obp_transaction.get.details.get.completed.get
|
||||
val balance = env.obp_transaction.get.details.get.new_balance.get.amount.get
|
||||
new TransactionImpl(id, thisBankAccount, otherAccount, metadata, transactionType, amount, currency,
|
||||
label, startDate, finishDate, balance)
|
||||
}
|
||||
|
||||
def getTransactions(permalink: String, bankPermalink: String, envelopesForAccount: Account => List[OBPEnvelope]): Box[List[Transaction]] =
|
||||
{
|
||||
logger.debug("getTransactions for " + bankPermalink + "/" + permalink)
|
||||
HostedBank.find("permalink",bankPermalink) match {
|
||||
case Full (bank) => bank.getAccount(permalink) match {
|
||||
case Full(account) => {
|
||||
val envs = envelopesForAccount(account)
|
||||
Full(envs.map(createTransaction(_, account)))
|
||||
}
|
||||
case _ => Empty
|
||||
}
|
||||
case _ => Empty
|
||||
}
|
||||
val uuid = id
|
||||
val otherAccountMetadata =
|
||||
new OtherBankAccountMetadata(
|
||||
publicAlias = oAcc.publicAlias.get,
|
||||
privateAlias = oAcc.privateAlias.get,
|
||||
moreInfo = oAcc.moreInfo.get,
|
||||
url = oAcc.url.get,
|
||||
imageURL = oAcc.imageUrl.get,
|
||||
openCorporatesURL = oAcc.openCorporatesUrl.get,
|
||||
corporateLocation = oAcc.corporateLocation.get,
|
||||
physicalLocation = oAcc.physicalLocation.get,
|
||||
addMoreInfo = (text => {
|
||||
oAcc.moreInfo(text).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addURL = (text => {
|
||||
oAcc.url(text).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addImageURL = (text => {
|
||||
oAcc.imageUrl(text).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addOpenCorporatesURL = (text => {
|
||||
oAcc.openCorporatesUrl(text).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addCorporateLocation = oAcc.addCorporateLocation,
|
||||
addPhysicalLocation = oAcc.addPhysicalLocation,
|
||||
addPublicAlias = (alias => {
|
||||
oAcc.publicAlias(alias).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addPrivateAlias = (alias => {
|
||||
oAcc.privateAlias(alias).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
deleteCorporateLocation = oAcc.deleteCorporateLocation _,
|
||||
deletePhysicalLocation = oAcc.deletePhysicalLocation _
|
||||
)
|
||||
val otherAccount = new OtherBankAccount(
|
||||
id = oAcc.id.is.toString,
|
||||
label = otherAccount_.holder.get,
|
||||
nationalIdentifier = otherAccount_.bank.get.national_identifier.get,
|
||||
swift_bic = None, //TODO: need to add this to the json/model
|
||||
iban = Some(otherAccount_.bank.get.IBAN.get),
|
||||
number = otherAccount_.number.get,
|
||||
bankName = otherAccount_.bank.get.name.get,
|
||||
metadata = otherAccountMetadata,
|
||||
kind = ""
|
||||
)
|
||||
val metadata = new TransactionMetadata(
|
||||
env.narrative.get,
|
||||
(text => env.narrative(text).save),
|
||||
env.obp_comments.objs,
|
||||
env.addComment,
|
||||
env.deleteComment,
|
||||
env.tags.objs,
|
||||
env.addTag,
|
||||
env.deleteTag,
|
||||
env.images.objs,
|
||||
env.addImage,
|
||||
env.deleteImage,
|
||||
env.whereTags.get,
|
||||
env.addWhereTag,
|
||||
env.deleteWhereTag
|
||||
)
|
||||
val transactionType = transaction.details.get.type_en.get
|
||||
val amount = transaction.details.get.value.get.amount.get
|
||||
val currency = transaction.details.get.value.get.currency.get
|
||||
val label = Some(transaction.details.get.label.get)
|
||||
val startDate = transaction.details.get.posted.get
|
||||
val finishDate = transaction.details.get.completed.get
|
||||
val balance = transaction.details.get.new_balance.get.amount.get
|
||||
new Transaction(
|
||||
uuid,
|
||||
id,
|
||||
thisBankAccount,
|
||||
otherAccount,
|
||||
metadata,
|
||||
transactionType,
|
||||
amount,
|
||||
currency,
|
||||
label,
|
||||
startDate,
|
||||
finishDate,
|
||||
balance
|
||||
)
|
||||
}
|
||||
|
||||
def getBank(permalink: String): Box[Bank] =
|
||||
HostedBank.find("permalink", permalink).
|
||||
map( bank => new BankImpl(bank.id.toString, bank.name.get, permalink))
|
||||
|
||||
|
||||
def allBanks : List[Bank] =
|
||||
HostedBank.findAll.
|
||||
map(bank => new BankImpl(bank.id.toString, bank.name.get, bank.permalink.get))
|
||||
|
||||
def getBankAccounts(bank: Bank): Set[BankAccount] = {
|
||||
val bankId = new ObjectId(bank.id)
|
||||
val rawAccounts = Account.findAll(("bankID" -> bankId)).toSet
|
||||
rawAccounts.map(Account.toBankAccount)
|
||||
private def createOtherBankAccount(otherAccount : OtherAccount, otherAccountFromTransaction : OBPAccount) : OtherBankAccount = {
|
||||
val metadata =
|
||||
new OtherBankAccountMetadata(
|
||||
publicAlias = otherAccount.publicAlias.get,
|
||||
privateAlias = otherAccount.privateAlias.get,
|
||||
moreInfo = otherAccount.moreInfo.get,
|
||||
url = otherAccount.url.get,
|
||||
imageURL = otherAccount.imageUrl.get,
|
||||
openCorporatesURL = otherAccount.openCorporatesUrl.get,
|
||||
corporateLocation = otherAccount.corporateLocation.get,
|
||||
physicalLocation = otherAccount.physicalLocation.get,
|
||||
addMoreInfo = (text => {
|
||||
otherAccount.moreInfo(text).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addURL = (text => {
|
||||
otherAccount.url(text).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addImageURL = (text => {
|
||||
otherAccount.imageUrl(text).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addOpenCorporatesURL = (text => {
|
||||
otherAccount.openCorporatesUrl(text).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addCorporateLocation = otherAccount.addCorporateLocation,
|
||||
addPhysicalLocation = otherAccount.addPhysicalLocation,
|
||||
addPublicAlias = (alias => {
|
||||
otherAccount.publicAlias(alias).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
addPrivateAlias = (alias => {
|
||||
otherAccount.privateAlias(alias).save
|
||||
//the save method does not return a Boolean to inform about the saving state,
|
||||
//so we a true
|
||||
true
|
||||
}),
|
||||
deleteCorporateLocation = otherAccount.deleteCorporateLocation _,
|
||||
deletePhysicalLocation = otherAccount.deletePhysicalLocation _
|
||||
)
|
||||
|
||||
new OtherBankAccount(
|
||||
id = otherAccount.id.is.toString,
|
||||
label = otherAccount.holder.get,
|
||||
nationalIdentifier = otherAccountFromTransaction.bank.get.national_identifier.get,
|
||||
swift_bic = None, //TODO: need to add this to the json/model
|
||||
iban = Some(otherAccountFromTransaction.bank.get.IBAN.get),
|
||||
number = otherAccountFromTransaction.number.get,
|
||||
bankName = otherAccountFromTransaction.bank.get.name.get,
|
||||
metadata = metadata,
|
||||
kind = ""
|
||||
)
|
||||
}
|
||||
|
||||
//check if the bank and the accounts exist in the database
|
||||
def correctBankAndAccount(bank: String, account: String): Boolean =
|
||||
HostedBank.find("permalink",bank) match {
|
||||
case Full(bank) => bank.isAccount(account)
|
||||
case _ => false
|
||||
}
|
||||
def getAccount(bankpermalink: String, account: String): Box[Account] =
|
||||
HostedBank.find("permalink",bankpermalink) match {
|
||||
case Full (bank) => bank.getAccount(account)
|
||||
case _ => Empty
|
||||
|
||||
private def setPrivilegeFromView(privilege : Privilege, view : View, value : Boolean ) = {
|
||||
view match {
|
||||
case OurNetwork => privilege.ourNetworkPermission(value)
|
||||
case Team => privilege.teamPermission(value)
|
||||
case Board => privilege.boardPermission(value)
|
||||
case Authorities => privilege.authoritiesPermission(value)
|
||||
case Owner => privilege.ownerPermission(value)
|
||||
case Management => privilege.mangementPermission(value)
|
||||
case _ =>
|
||||
}
|
||||
|
||||
def getTransaction(id : String, bankPermalink : String, accountPermalink : String) : Box[Transaction] =
|
||||
{
|
||||
}
|
||||
|
||||
private def createBank(bank : HostedBank) : Bank = {
|
||||
new Bank(
|
||||
bank.id.is.toString,
|
||||
bank.alias.is,
|
||||
bank.name.is,
|
||||
bank.permalink.is,
|
||||
bank.logoURL.is,
|
||||
bank.website.is
|
||||
)
|
||||
}
|
||||
|
||||
private def getHostedBank(permalink : String) : Box[HostedBank] = {
|
||||
for{
|
||||
bank <- HostedBank.find("permalink",bankPermalink)
|
||||
bank <- HostedBank.find("permalink", permalink) ?~ {"bank " + permalink + " not found"}
|
||||
} yield bank
|
||||
}
|
||||
|
||||
private def getTransaction(id : String, bankPermalink : String, accountPermalink : String) : Box[Transaction] = {
|
||||
for{
|
||||
bank <- getHostedBank(bankPermalink)
|
||||
account <- bank.getAccount(accountPermalink)
|
||||
ifTransactionsIsInAccount <- Full(account.transactionsForAccount.put("_id").is(new ObjectId(id)).get)
|
||||
objectId <- tryo{new ObjectId(id)} ?~ {"Transaction "+id+" not found"}
|
||||
ifTransactionsIsInAccount <- Full(account.transactionsForAccount.put("_id").is(objectId).get)
|
||||
envelope <- OBPEnvelope.find(ifTransactionsIsInAccount)
|
||||
} yield createTransaction(envelope,account)
|
||||
}
|
||||
|
||||
def getAllAccounts() : List[Account] = Account.findAll
|
||||
private def getTransactions(permalink: String, bankPermalink: String, queryParams: OBPQueryParam*): Box[List[Transaction]] = {
|
||||
logger.debug("getTransactions for " + bankPermalink + "/" + permalink)
|
||||
for{
|
||||
bank <- getHostedBank(bankPermalink)
|
||||
account <- bank.getAccount(permalink)
|
||||
} yield account.envelopes(queryParams: _*).map(createTransaction(_, account))
|
||||
}
|
||||
|
||||
def getBank(permalink: String): Box[Bank] =
|
||||
for{
|
||||
bank <- getHostedBank(permalink)
|
||||
} yield createBank(bank)
|
||||
|
||||
def allBanks : List[Bank] =
|
||||
HostedBank.findAll.map(createBank)
|
||||
|
||||
//TODO: remove after the split because useless
|
||||
def getAccount(bankpermalink: String, account: String): Box[Account] =
|
||||
for{
|
||||
hostedBank <- getHostedBank(bankpermalink)
|
||||
account <- hostedBank.getAccount(account)
|
||||
} yield account
|
||||
|
||||
def getBankAccount(bankId : String, bankAccountId : String) : Box[BankAccount] = {
|
||||
for{
|
||||
bank <- getHostedBank(bankId)
|
||||
account <- bank.getAccount(bankAccountId)
|
||||
} yield Account toBankAccount account
|
||||
}
|
||||
|
||||
def getAllPublicAccounts() : List[BankAccount] = Account.findAll("anonAccess", true) map Account.toBankAccount
|
||||
|
||||
def getPublicBankAccounts(bank : Bank) : Box[List[BankAccount]] = {
|
||||
for{
|
||||
id <- tryo{new ObjectId(bank.id)} ?~ {"bank " + bank.fullName + " not found"}
|
||||
} yield Account.findAll(("bankID",id) ~ ("anonAccess", true)).map(Account.toBankAccount)
|
||||
}
|
||||
|
||||
def getAllPublicAccounts() : List[Account] = Account.findAll("anonAccess", true)
|
||||
private def moreThanAnonHostedAccounts(user : User) : Box[List[HostedAccount]] = {
|
||||
user match {
|
||||
case u : OBPUser => {
|
||||
val hostedAccountTable = HostedAccount._dbTableNameLC
|
||||
val privilegeTable = Privilege._dbTableNameLC
|
||||
val userTable = OBPUser._dbTableNameLC
|
||||
|
||||
val hostedId = hostedAccountTable + "." + HostedAccount.id.dbColumnName
|
||||
val hostedAccId = hostedAccountTable + "." + HostedAccount.accountID.dbColumnName
|
||||
val privilegeAccId = privilegeTable + "." + Privilege.account.dbColumnName
|
||||
val privilegeUserId = privilegeTable + "." + Privilege.user.dbColumnName
|
||||
|
||||
val ourNetworkPrivilege = privilegeTable + "." + Privilege.ourNetworkPermission.dbColumnName
|
||||
val teamPrivilege = privilegeTable + "." + Privilege.teamPermission.dbColumnName
|
||||
val boardPrivilege = privilegeTable + "." + Privilege.boardPermission.dbColumnName
|
||||
val authoritiesPrivilege = privilegeTable + "." + Privilege.authoritiesPermission.dbColumnName
|
||||
val ownerPrivilege = privilegeTable + "." + Privilege.ownerPermission.dbColumnName
|
||||
val managementPrivilege = privilegeTable + "." + Privilege.mangementPermission.dbColumnName
|
||||
|
||||
val query = "SELECT DISTINCT " + hostedId + ", " + hostedAccId +
|
||||
" FROM " + hostedAccountTable + ", " + privilegeTable + ", " + userTable +
|
||||
" WHERE " + "( " + hostedId + " = " + privilegeAccId + ")" +
|
||||
" AND " + "( " + privilegeUserId + " = ? "/* + u.id.get*/ + ")"+
|
||||
" AND " + "( " + ourNetworkPrivilege + " = true" +
|
||||
" OR " + teamPrivilege + " = true" +
|
||||
" OR " + boardPrivilege + " = true" +
|
||||
" OR " + authoritiesPrivilege + " = true" +
|
||||
" OR " + managementPrivilege + " = true" +
|
||||
" OR " + ownerPrivilege + " = true)"
|
||||
|
||||
Full(HostedAccount.findAllByPreparedStatement({
|
||||
superconn => {
|
||||
val statement = superconn.connection.prepareStatement(query)
|
||||
statement.setLong(1, u.id.get)
|
||||
statement
|
||||
}
|
||||
}))
|
||||
}
|
||||
case _ => {
|
||||
logger.error("OBPUser instance not found, could not execute the SQL query ")
|
||||
Failure("could not find non public bank accounts")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bank accounts where the user has at least access to a non public view (is_public==false)
|
||||
*/
|
||||
def getNonPublicBankAccounts(user : User) : Box[List[BankAccount]] = {
|
||||
|
||||
user match {
|
||||
case u : OBPUser => {
|
||||
|
||||
for {
|
||||
moreThanAnon <- moreThanAnonHostedAccounts(u)
|
||||
} yield {
|
||||
val mongoIds = moreThanAnon.map(hAcc => new ObjectId(hAcc.accountID.get))
|
||||
Account.findAll(mongoIds).map(Account.toBankAccount)
|
||||
}
|
||||
|
||||
}
|
||||
case u: User => {
|
||||
logger.error("OBPUser instance not found, could not execute the SQL query ")
|
||||
Failure("could not find non public bank accounts")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bank accounts where the user has at least access to a non public view (is_public==false) for a specific bank
|
||||
*/
|
||||
def getNonPublicBankAccounts(user : User, bankID : String) : Box[List[BankAccount]] = {
|
||||
user match {
|
||||
case u : OBPUser => {
|
||||
|
||||
for {
|
||||
moreThanAnon <- moreThanAnonHostedAccounts(u)
|
||||
bankObjectId <- tryo{new ObjectId(bankID)}
|
||||
} yield {
|
||||
|
||||
def sameBank(account : Account) : Boolean =
|
||||
account.bankID.get == bankObjectId
|
||||
|
||||
val mongoIds = moreThanAnon.map(hAcc => new ObjectId(hAcc.accountID.get))
|
||||
Account.findAll(mongoIds).filter(sameBank).map(Account.toBankAccount)
|
||||
}
|
||||
|
||||
}
|
||||
case u : User => {
|
||||
logger.error("OBPUser instance not found, could not execute the SQL query ")
|
||||
Failure("could not find non public bank accounts")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: remove after the split because useless
|
||||
def correctBankAndAccount(bank: String, account: String): Boolean =
|
||||
getHostedBank(bank) match {
|
||||
case Full(bank) => bank.isAccount(account)
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def getModeratedOtherBankAccount(accountID : String, otherAccountID : String)
|
||||
(moderate: OtherBankAccount => Option[ModeratedOtherBankAccount]): Box[ModeratedOtherBankAccount] = {
|
||||
for{
|
||||
id <- tryo{new ObjectId(accountID)} ?~ {"account " + accountID + " not found"}
|
||||
account <- Account.find("_id",id)
|
||||
otherAccount <- account.otherAccounts.objs.find(_.id.get.equals(otherAccountID))
|
||||
} yield{
|
||||
val otherAccountFromTransaction : OBPAccount = OBPEnvelope.find("obp_transaction.other_account.holder",otherAccount.holder.get) match {
|
||||
case Full(envelope) =>
|
||||
envelope.obp_transaction.get.other_account.get
|
||||
case _ => OBPAccount.createRecord
|
||||
}
|
||||
moderate(createOtherBankAccount(otherAccount, otherAccountFromTransaction)).get
|
||||
}
|
||||
}
|
||||
|
||||
def getModeratedOtherBankAccounts(accountID : String)
|
||||
(moderate: OtherBankAccount => Option[ModeratedOtherBankAccount]): Box[List[ModeratedOtherBankAccount]] = {
|
||||
for{
|
||||
id <- tryo{new ObjectId(accountID)} ?~ {"account " + accountID + " not found"}
|
||||
account <- Account.find("_id",id)
|
||||
} yield{
|
||||
val otherBankAccounts = account.otherAccounts.objs.map(otherAccount => {
|
||||
//for legacy reasons some of the data about the "other account" are stored only on the transactions
|
||||
//so we need first to get a transaction that match to have the rest of the data
|
||||
val otherAccountFromTransaction : OBPAccount = OBPEnvelope.find("obp_transaction.other_account.holder",otherAccount.holder.get) match {
|
||||
case Full(envelope) =>
|
||||
envelope.obp_transaction.get.other_account.get
|
||||
case _ => OBPAccount.createRecord
|
||||
}
|
||||
createOtherBankAccount(otherAccount, otherAccountFromTransaction)
|
||||
})
|
||||
|
||||
(otherBankAccounts.map(moderate)).collect{case Some(t) => t}
|
||||
}
|
||||
}
|
||||
|
||||
def getModeratedTransactions(permalink: String, bankPermalink: String, queryParams: OBPQueryParam*)
|
||||
(moderate: Transaction => ModeratedTransaction): Box[List[ModeratedTransaction]] = {
|
||||
for{
|
||||
rawTransactions <- getTransactions(permalink, bankPermalink, queryParams: _*)
|
||||
} yield rawTransactions.map(moderate)
|
||||
}
|
||||
|
||||
def getUser(id : String) : Box[User] =
|
||||
OBPUser.find(By(OBPUser.email,id)) match {
|
||||
case Full(u) => Full(u)
|
||||
case _ => Failure("user " + id + " not found")
|
||||
}
|
||||
|
||||
def getModeratedTransaction(id : String, bankPermalink : String, accountPermalink : String)
|
||||
(moderate: Transaction => ModeratedTransaction) : Box[ModeratedTransaction] = {
|
||||
for{
|
||||
transaction <- getTransaction(id,bankPermalink,accountPermalink)
|
||||
} yield moderate(transaction)
|
||||
}
|
||||
|
||||
def getCurrentUser : Box[User] = OBPUser.currentUser
|
||||
|
||||
def permissions(account : BankAccount) : Box[List[Permission]] = {
|
||||
|
||||
HostedAccount.find(By(HostedAccount.accountID,account.id)) match {
|
||||
case Full(acc) => {
|
||||
val privileges = Privilege.findAll(By(Privilege.account, acc.id.get)).sortWith((p1,p2) => p1.updatedAt.get after p2.updatedAt.get)
|
||||
val permissions : List[Box[Permission]] = privileges.map( p => {
|
||||
if(
|
||||
p.ourNetworkPermission.get != false
|
||||
| p.teamPermission.get != false
|
||||
| p.boardPermission.get != false
|
||||
| p.authoritiesPermission.get != false
|
||||
| p.ownerPermission.get != false
|
||||
| p.mangementPermission.get != false
|
||||
)
|
||||
p.user.obj.map(u => {
|
||||
new Permission(
|
||||
u,
|
||||
u.permittedViews(account).toList
|
||||
)
|
||||
})
|
||||
else
|
||||
Empty
|
||||
})
|
||||
Full(permissions.flatten)
|
||||
}
|
||||
case _ => Failure("Could not find the hostedAccount", Empty, Empty)
|
||||
}
|
||||
}
|
||||
|
||||
def addPermission(bankAccountId : String, view : View, user : User) : Box[Boolean] = {
|
||||
user match {
|
||||
case u: OBPUser =>
|
||||
for{
|
||||
bankAccount <- HostedAccount.find(By(HostedAccount.accountID, bankAccountId))
|
||||
} yield {
|
||||
Privilege.find(By(Privilege.user, u.id), By(Privilege.account, bankAccount)) match {
|
||||
//update the existing privilege
|
||||
case Full(privilege) => {
|
||||
setPrivilegeFromView(privilege, view, true)
|
||||
privilege.save
|
||||
}
|
||||
//there is no privilege to this user, so we create one
|
||||
case _ => {
|
||||
val privilege =
|
||||
Privilege.create.
|
||||
user(u.id).
|
||||
account(bankAccount)
|
||||
setPrivilegeFromView(privilege, view, true)
|
||||
privilege.save
|
||||
}
|
||||
}
|
||||
}
|
||||
case u: User => {
|
||||
logger.error("OBPUser instance not found, could not grant access ")
|
||||
Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def addPermissions(bankAccountId : String, views : List[View], user : User) : Box[Boolean] ={
|
||||
user match {
|
||||
case u : OBPUser => {
|
||||
for{
|
||||
bankAccount <- HostedAccount.find(By(HostedAccount.accountID, bankAccountId))
|
||||
} yield {
|
||||
Privilege.find(By(Privilege.user, u.id), By(Privilege.account, bankAccount)) match {
|
||||
//update the existing privilege
|
||||
case Full(privilege) => {
|
||||
views.map(v => {
|
||||
setPrivilegeFromView(privilege, v, true)
|
||||
})
|
||||
privilege.save
|
||||
}
|
||||
//there is no privilege to this user, so we create one
|
||||
case _ => {
|
||||
val privilege =
|
||||
Privilege.create.
|
||||
user(u.id).
|
||||
account(bankAccount)
|
||||
views.map(v => {
|
||||
setPrivilegeFromView(privilege, v, true)
|
||||
})
|
||||
privilege.save
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case u: User => {
|
||||
logger.error("OBPUser instance not found, could not grant access ")
|
||||
Empty
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
def revokePermission(bankAccountId : String, view : View, user : User) : Box[Boolean] = {
|
||||
user match {
|
||||
case user:OBPUser =>
|
||||
for{
|
||||
bankAccount <- HostedAccount.find(By(HostedAccount.accountID, bankAccountId))
|
||||
} yield {
|
||||
Privilege.find(By(Privilege.user, user.id), By(Privilege.account, bankAccount)) match {
|
||||
case Full(privilege) => {
|
||||
setPrivilegeFromView(privilege, view, false)
|
||||
privilege.save
|
||||
}
|
||||
//there is no privilege to this user, so there is nothing to revoke
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
case u: User => {
|
||||
logger.error("OBPUser instance not found, could not revoke access ")
|
||||
Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def revokeAllPermission(bankAccountId : String, user : User) : Box[Boolean] = {
|
||||
user match {
|
||||
case user:OBPUser =>
|
||||
for{
|
||||
bankAccount <- HostedAccount.find(By(HostedAccount.accountID, bankAccountId))
|
||||
} yield {
|
||||
Privilege.find(By(Privilege.user, user.id), By(Privilege.account, bankAccount)) match {
|
||||
case Full(privilege) => {
|
||||
availableViews.foreach({view =>
|
||||
setPrivilegeFromView(privilege, view, false)
|
||||
})
|
||||
privilege.save
|
||||
}
|
||||
//there is no privilege to this user, so there is nothing to revoke
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
case u: User => {
|
||||
logger.error("OBPUser instance not found, could not revoke access ")
|
||||
Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def views(bankAccountID : String) : Box[List[View]] = {
|
||||
Full(availableViews)
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -43,10 +43,16 @@ object AdminDb extends MongoIdentifier {
|
||||
object MongoConfig {
|
||||
def init: Unit = {
|
||||
val srvr = new ServerAddress(
|
||||
Props.get("mongo.host", "obp_mongod"),
|
||||
Props.get("mongo.host", "localhost"),
|
||||
Props.getInt("mongo.port", 27017)
|
||||
)
|
||||
MongoDB.defineDb(DefaultMongoIdentifier, new Mongo(srvr), "OBP006")
|
||||
val defaultDatabase =
|
||||
Props.mode match {
|
||||
case Props.RunModes.Test => "test"
|
||||
case _ => "OBP006"
|
||||
}
|
||||
|
||||
MongoDB.defineDb(DefaultMongoIdentifier, new Mongo(srvr), Props.get("mongo.dbName", defaultDatabase))
|
||||
MongoDB.defineDb(AdminDb, new Mongo(srvr), "admin")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -47,8 +47,13 @@ import net.liftweb.mongodb.record.field.{MongoJsonObjectListField, MongoRefField
|
||||
import scala.util.Random
|
||||
import com.mongodb.QueryBuilder
|
||||
import com.mongodb.BasicDBObject
|
||||
import code.model.traits.Comment
|
||||
import code.model.{Comment,Tag,GeoTag,TransactionImage, User}
|
||||
import net.liftweb.common.Loggable
|
||||
import org.bson.types.ObjectId
|
||||
import net.liftweb.util.Helpers._
|
||||
import net.liftweb.http.S
|
||||
import java.net.URL
|
||||
import net.liftweb.record.field.{DoubleField,DecimalField}
|
||||
|
||||
/**
|
||||
* "Current Account View"
|
||||
@ -141,38 +146,25 @@ curl -i -H "Content-Type: application/json" -X POST -d '[{
|
||||
*/
|
||||
|
||||
// Seems to map to a collection of the plural name
|
||||
class OBPEnvelope private() extends MongoRecord[OBPEnvelope] with ObjectIdPk[OBPEnvelope] {
|
||||
class OBPEnvelope private() extends MongoRecord[OBPEnvelope] with ObjectIdPk[OBPEnvelope] with Loggable{
|
||||
def meta = OBPEnvelope
|
||||
|
||||
/**
|
||||
* Add a user generated comment to the transaction. Saves the db model when called.
|
||||
*
|
||||
* @param email The email address of the person posting the comment
|
||||
* @param text The text of the comment
|
||||
*/
|
||||
def addComment(userId: Long, viewId : Long, text: String, datePosted : Date) = {
|
||||
val comment = OBPComment.createRecord.userId(userId).
|
||||
textField(text).
|
||||
date(datePosted).
|
||||
viewID(viewId).save
|
||||
obp_comments(comment.id.is :: obp_comments.get ).save
|
||||
}
|
||||
// This creates a json attribute called "obp_transaction"
|
||||
object obp_transaction extends BsonRecordField(this, OBPTransaction)
|
||||
|
||||
object narrative extends StringField(this, 255)
|
||||
|
||||
//not named comments as "comments" was used in an older mongo document version
|
||||
object obp_comments extends ObjectIdRefListField[OBPEnvelope, OBPComment](this, OBPComment)
|
||||
|
||||
object tags extends ObjectIdRefListField(this, OBPTag)
|
||||
|
||||
object images extends ObjectIdRefListField(this, OBPTransactionImage)
|
||||
|
||||
//we store a list of geo tags, one per view
|
||||
object whereTags extends BsonRecordListField(this, OBPGeoTag)
|
||||
|
||||
|
||||
lazy val theAccount = {
|
||||
val thisAcc = obp_transaction.get.this_account.get
|
||||
val num = thisAcc.number.get
|
||||
val accKind = thisAcc.kind.get
|
||||
val bankName = thisAcc.bank.get.name.get
|
||||
val accQry = QueryBuilder.start("number").is(num).
|
||||
put("kind").is(accKind).get
|
||||
|
||||
for {
|
||||
account <- Account.find(accQry)
|
||||
bank <- HostedBank.find("name", bankName)
|
||||
if(bank.id.get == account.bankID.get)
|
||||
} yield account
|
||||
}
|
||||
|
||||
object DateDescending extends Ordering[OBPEnvelope] {
|
||||
def compare(e1: OBPEnvelope, e2: OBPEnvelope) = {
|
||||
val date1 = e1.obp_transaction.get.details.get.completed.get
|
||||
@ -180,20 +172,205 @@ class OBPEnvelope private() extends MongoRecord[OBPEnvelope] with ObjectIdPk[OBP
|
||||
date1.compareTo(date2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lazy val theAccount = {
|
||||
val thisAcc = obp_transaction.get.this_account.get
|
||||
val num = thisAcc.number.get
|
||||
val accKind = thisAcc.kind.get
|
||||
val bankName = thisAcc.bank.get.name.get
|
||||
val holder = thisAcc.holder.get
|
||||
val accQry = QueryBuilder.start("number").is(num).
|
||||
put("kind").is(accKind).put("holder").is(holder).get
|
||||
|
||||
for {
|
||||
account <- Account.find(accQry)
|
||||
bank <- HostedBank.find("name", bankName)
|
||||
if(bank.id.get == account.bankID.get)
|
||||
} yield account
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user generated comment to the transaction. Saves the db model when called.
|
||||
*
|
||||
* @param email The email address of the person posting the comment
|
||||
* @param text The text of the comment
|
||||
*/
|
||||
def addComment(userId: String, viewId : Long, text: String, datePosted : Date) : Comment = {
|
||||
val comment = OBPComment.createRecord.userId(userId).
|
||||
textField(text).
|
||||
date(datePosted).
|
||||
viewID(viewId).save
|
||||
obp_comments(comment.id.is :: obp_comments.get ).save
|
||||
comment
|
||||
}
|
||||
|
||||
def deleteComment(id : String) : Box[Unit]= {
|
||||
OBPComment.find(id) match {
|
||||
case Full(comment) => {
|
||||
if(comment.delete_!){
|
||||
obp_comments(obp_comments.get.diff(Seq(new ObjectId(id)))).save
|
||||
Full()
|
||||
}
|
||||
else Failure("Delete not completed")
|
||||
}
|
||||
case _ => Failure("Comment "+id+" not found")
|
||||
}
|
||||
}
|
||||
|
||||
def addWhereTag(userId: String, viewId : Long, datePosted : Date, longitude : Double, latitude : Double) : Boolean = {
|
||||
val newTag = OBPGeoTag.createRecord.
|
||||
userId(userId).
|
||||
viewID(viewId).
|
||||
date(datePosted).
|
||||
geoLongitude(longitude).
|
||||
geoLatitude(latitude)
|
||||
|
||||
|
||||
//before to save the geo tag we need to be sure there is only one per view
|
||||
//so we look if there is allready a tag with the same view (viewId)
|
||||
val tags = whereTags.get.find(geoTag => geoTag.viewID equals viewId) match {
|
||||
case Some(tag) => {
|
||||
//if true remplace it with the new one
|
||||
newTag :: whereTags.get.diff(Seq(tag))
|
||||
}
|
||||
case _ =>
|
||||
//else just add this one
|
||||
newTag :: whereTags.get
|
||||
}
|
||||
whereTags(tags).save
|
||||
true
|
||||
}
|
||||
|
||||
def deleteWhereTag(viewId : Long):Boolean = {
|
||||
val where :Option[OBPGeoTag] = whereTags.get.find(loc=>{loc.viewId ==viewId})
|
||||
where match {
|
||||
case Some(w) => {
|
||||
val newWhereTags = whereTags.get.diff(Seq(w))
|
||||
whereTags(newWhereTags).save
|
||||
true
|
||||
}
|
||||
case None => false
|
||||
}
|
||||
}
|
||||
|
||||
def addTag(userId: String, viewId : Long, value: String, datePosted : Date) : Tag = {
|
||||
val tag = OBPTag.createRecord.
|
||||
userId(userId).
|
||||
tag(value).
|
||||
date(datePosted).
|
||||
viewID(viewId).save
|
||||
tags(tag.id.is :: tags.get ).save
|
||||
tag
|
||||
}
|
||||
|
||||
def deleteTag(id : String) : Box[Unit] = {
|
||||
OBPTag.find(id) match {
|
||||
case Full(tag) => {
|
||||
if(tag.delete_!){
|
||||
tags(tags.get.diff(Seq(new ObjectId(id)))).save
|
||||
Full()
|
||||
}
|
||||
else Failure("Delete not completed")
|
||||
}
|
||||
case _ => Failure("Tag "+id+" not found")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id of the newly added image
|
||||
*/
|
||||
def addImage(userId: String, viewId : Long, description: String, datePosted : Date, imageURL : URL) : TransactionImage = {
|
||||
val image = OBPTransactionImage.createRecord.
|
||||
userId(userId).imageComment(description).date(datePosted).viewID(viewId).url(imageURL.toString).save
|
||||
images(image.id.is :: images.get).save
|
||||
image
|
||||
}
|
||||
|
||||
def deleteImage(id : String){
|
||||
OBPTransactionImage.find(id) match {
|
||||
case Full(image) => {
|
||||
//if(image.postedBy.isDefined && image.postedBy.get.id.get == userId) {
|
||||
if (image.delete_!) {
|
||||
logger.info("==> deleted image id : " + id)
|
||||
images(images.get.diff(Seq(new ObjectId(id)))).save
|
||||
//TODO: Delete the actual image file? We don't always control the url of the image so we can't always delete it
|
||||
}
|
||||
}
|
||||
case _ => logger.warn("Could not find image with id " + id + " to delete.")
|
||||
}
|
||||
}
|
||||
|
||||
def orderByDateDescending = (e1: OBPEnvelope, e2: OBPEnvelope) => {
|
||||
val date1 = e1.obp_transaction.get.details.get.completed.get
|
||||
val date2 = e2.obp_transaction.get.details.get.completed.get
|
||||
date1.after(date2)
|
||||
}
|
||||
|
||||
// This creates a json attribute called "obp_transaction"
|
||||
object obp_transaction extends BsonRecordField(this, OBPTransaction)
|
||||
|
||||
//not named comments as "comments" was used in an older mongo document version
|
||||
object obp_comments extends ObjectIdRefListField[OBPEnvelope, OBPComment](this, OBPComment)
|
||||
object narrative extends StringField(this, 255)
|
||||
|
||||
def createAliases : Box[String] = {
|
||||
val realOtherAccHolder = this.obp_transaction.get.other_account.get.holder.get
|
||||
|
||||
def publicAliasExists(realValue: String): Boolean = {
|
||||
this.theAccount match {
|
||||
case Full(a) => {
|
||||
val otherAccs = a.otherAccounts.objs
|
||||
val aliasInQuestion = otherAccs.find(o =>
|
||||
o.holder.get.equals(realValue))
|
||||
aliasInQuestion.isDefined
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def createPublicAlias(realOtherAccHolder : String) : Box[String] = {
|
||||
|
||||
/**
|
||||
* Generates a new alias name that is guaranteed not to collide with any existing public alias names
|
||||
* for the account in question
|
||||
*/
|
||||
def newPublicAliasName(account: Account): String = {
|
||||
val firstAliasAttempt = "ALIAS_" + Random.nextLong().toString.take(6)
|
||||
|
||||
/**
|
||||
* Returns true if @publicAlias is already the name of a public alias within @account
|
||||
*/
|
||||
def isDuplicate(publicAlias: String, account: Account) = {
|
||||
account.otherAccounts.objs.find(oAcc => {
|
||||
oAcc.publicAlias.get == publicAlias
|
||||
}).isDefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends things to @publicAlias until it a unique public alias name within @account
|
||||
*/
|
||||
def appendUntilUnique(publicAlias: String, account: Account): String = {
|
||||
val newAlias = publicAlias + Random.nextLong().toString.take(1)
|
||||
if (isDuplicate(newAlias, account)) appendUntilUnique(newAlias, account)
|
||||
else newAlias
|
||||
}
|
||||
|
||||
if (isDuplicate(firstAliasAttempt, account)) appendUntilUnique(firstAliasAttempt, account)
|
||||
else firstAliasAttempt
|
||||
}
|
||||
|
||||
this.theAccount match {
|
||||
case Full(a) => {
|
||||
val randomAliasName = newPublicAliasName(a)
|
||||
//create a new "otherAccount"
|
||||
val otherAccount = OtherAccount.createRecord.holder(realOtherAccHolder).publicAlias(randomAliasName).save
|
||||
a.otherAccounts(otherAccount.id.is :: a.otherAccounts.get).save
|
||||
Full(randomAliasName)
|
||||
}
|
||||
case _ => {
|
||||
logger.warn("Account not found to create aliases for")
|
||||
Failure("Account not found to create aliases for")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!publicAliasExists(realOtherAccHolder))
|
||||
createPublicAlias(realOtherAccHolder)
|
||||
else
|
||||
Full(realOtherAccHolder)
|
||||
}
|
||||
/**
|
||||
* A JSON representation of the transaction to be returned when successfully added via an API call
|
||||
*/
|
||||
@ -207,21 +384,23 @@ class OBPEnvelope private() extends MongoRecord[OBPEnvelope] with ObjectIdPk[OBP
|
||||
|
||||
class OBPComment private() extends MongoRecord[OBPComment] with ObjectIdPk[OBPComment] with Comment {
|
||||
def meta = OBPComment
|
||||
def postedBy = OBPUser.find(userId)
|
||||
def postedBy = User.findById(userId.get)
|
||||
def viewId = viewID.get
|
||||
def text = textField.get
|
||||
def datePosted = date.get
|
||||
def id_ = id.is.toString
|
||||
object userId extends LongField(this)
|
||||
def replyToID = replyTo.get
|
||||
object userId extends StringField(this,255)
|
||||
object viewID extends LongField(this)
|
||||
object textField extends StringField(this, 255)
|
||||
object date extends DateField(this)
|
||||
object replyTo extends StringField(this,255)
|
||||
}
|
||||
|
||||
object OBPComment extends OBPComment with MongoMetaRecord[OBPComment]
|
||||
|
||||
object OBPEnvelope extends OBPEnvelope with MongoMetaRecord[OBPEnvelope] with Loggable {
|
||||
|
||||
|
||||
class OBPQueryParam
|
||||
trait OBPOrder { def orderValue : Int }
|
||||
object OBPOrder {
|
||||
@ -237,143 +416,28 @@ object OBPEnvelope extends OBPEnvelope with MongoMetaRecord[OBPEnvelope] with Lo
|
||||
case class OBPFromDate(value: Date) extends OBPQueryParam
|
||||
case class OBPToDate(value: Date) extends OBPQueryParam
|
||||
case class OBPOrdering(field: Option[String], order: OBPOrder) extends OBPQueryParam
|
||||
|
||||
override def fromJValue(jval: JValue) = {
|
||||
|
||||
def createAliases(env: OBPEnvelope) = {
|
||||
val realOtherAccHolder = env.obp_transaction.get.other_account.get.holder.get
|
||||
|
||||
def publicAliasExists(realValue: String): Boolean = {
|
||||
env.theAccount match {
|
||||
case Full(a) => {
|
||||
val otherAccs = a.otherAccounts.get
|
||||
val aliasInQuestion = otherAccs.find(o =>
|
||||
o.holder.get.equals(realValue))
|
||||
aliasInQuestion.isDefined
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def privateAliasExists(realValue: String): Boolean = {
|
||||
env.theAccount match {
|
||||
case Full(a) => {
|
||||
val otherAccs = a.otherAccounts.get
|
||||
val aliasInQuestion = otherAccs.find(o =>
|
||||
o.holder.get.equals(realValue))
|
||||
aliasInQuestion.isDefined
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def createPublicAlias() = {
|
||||
//TODO: Guarantee a unique public alias string
|
||||
|
||||
/**
|
||||
* Generates a new alias name that is guaranteed not to collide with any existing public alias names
|
||||
* for the account in question
|
||||
*/
|
||||
def newPublicAliasName(account: Account): String = {
|
||||
val newAlias = "ALIAS_" + Random.nextLong().toString.take(6)
|
||||
|
||||
/**
|
||||
* Returns true if @publicAlias is already the name of a public alias within @account
|
||||
*/
|
||||
def isDuplicate(publicAlias: String, account: Account) = {
|
||||
account.otherAccounts.get.find(oAcc => {
|
||||
oAcc.publicAlias.get == newAlias
|
||||
}).isDefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends things to @publicAlias until it a unique public alias name within @account
|
||||
*/
|
||||
def appendUntilUnique(publicAlias: String, account: Account): String = {
|
||||
val newAlias = publicAlias + Random.nextLong().toString.take(1)
|
||||
if (isDuplicate(newAlias, account)) appendUntilUnique(newAlias, account)
|
||||
else newAlias
|
||||
}
|
||||
|
||||
if (isDuplicate(newAlias, account)) appendUntilUnique(newAlias, account)
|
||||
else newAlias
|
||||
}
|
||||
|
||||
env.theAccount match {
|
||||
case Full(a) => {
|
||||
val randomAliasName = newPublicAliasName(a)
|
||||
val oAccHolderName = env.obp_transaction.get.other_account.get.holder.get
|
||||
val otherAccount = a.otherAccounts.get.find(acc => acc.holder.equals(oAccHolderName))
|
||||
val updatedAccount = otherAccount match {
|
||||
case Some(o) => {
|
||||
//update the "otherAccount"
|
||||
val newOtherAcc = o.publicAlias(randomAliasName)
|
||||
a.otherAccounts(a.otherAccounts.get -- List(o) ++ List(newOtherAcc))
|
||||
}
|
||||
case _ => {
|
||||
//create a new "otherAccount"
|
||||
a.otherAccounts(a.otherAccounts.get ++ List(OtherAccount.createRecord.holder(oAccHolderName).publicAlias(randomAliasName)))
|
||||
}
|
||||
}
|
||||
|
||||
updatedAccount.saveTheRecord()
|
||||
Full(randomAliasName)
|
||||
}
|
||||
case _ => {
|
||||
logger.warn("Account not found to create aliases for")
|
||||
Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def createPlaceholderPrivateAlias() = {
|
||||
env.theAccount match {
|
||||
case Full(a) => {
|
||||
val oAccHolderName = env.obp_transaction.get.other_account.get.holder.get
|
||||
val otherAccount = a.otherAccounts.get.find(acc => acc.holder.equals(oAccHolderName))
|
||||
val updatedAccount = otherAccount match {
|
||||
case Some(o) => {
|
||||
//update the "otherAccount"
|
||||
val newOtherAcc = o.privateAlias("")
|
||||
a.otherAccounts(a.otherAccounts.get -- List(o) ++ List(newOtherAcc))
|
||||
}
|
||||
case _ => {
|
||||
//create a new "otherAccount"
|
||||
a.otherAccounts(a.otherAccounts.get ++ List(OtherAccount.createRecord.holder(oAccHolderName)))
|
||||
}
|
||||
}
|
||||
updatedAccount.saveTheRecord()
|
||||
Full("")
|
||||
}
|
||||
case _ => Empty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!publicAliasExists(realOtherAccHolder)) {
|
||||
createPublicAlias()
|
||||
}
|
||||
if (!privateAliasExists(realOtherAccHolder)) createPlaceholderPrivateAlias()
|
||||
}
|
||||
|
||||
val created = super.fromJValue(jval)
|
||||
def envlopesFromJvalue(jval: JValue) : Box[OBPEnvelope] = {
|
||||
val created = fromJValue(jval)
|
||||
created match {
|
||||
case Full(c) => createAliases(c)
|
||||
case _ => //don't create anything
|
||||
case Full(c) => c.createAliases match {
|
||||
case Full(alias) => Full(c)
|
||||
case Failure(msg, _, _ ) => Failure(msg)
|
||||
case _ => Failure("Alias not created")
|
||||
}
|
||||
case _ => Failure("could not create Envelope form JValue")
|
||||
}
|
||||
created
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class OBPTransaction private() extends BsonRecord[OBPTransaction]{
|
||||
def meta = OBPTransaction
|
||||
|
||||
|
||||
object this_account extends BsonRecordField(this, OBPAccount)
|
||||
object other_account extends BsonRecordField(this, OBPAccount)
|
||||
object details extends BsonRecordField(this, OBPDetails)
|
||||
|
||||
|
||||
def whenAddedJson(envelopeId : String) : JObject = {
|
||||
JObject(List(JField("obp_transaction_uuid", JString(envelopeId)),
|
||||
JField("this_account", this_account.get.whenAddedJson),
|
||||
@ -421,7 +485,7 @@ class OBPBank private() extends BsonRecord[OBPBank]{
|
||||
object national_identifier extends net.liftweb.record.field.StringField(this, 255)
|
||||
object name extends net.liftweb.record.field.StringField(this, 255)
|
||||
|
||||
|
||||
|
||||
def whenAddedJson : JObject = {
|
||||
JObject(List( JField("IBAN", JString(IBAN.get)),
|
||||
JField("national_identifier", JString(national_identifier.get)),
|
||||
@ -443,12 +507,13 @@ class OBPDetails private() extends BsonRecord[OBPDetails]{
|
||||
object new_balance extends BsonRecordField(this, OBPBalance)
|
||||
object value extends BsonRecordField(this, OBPValue)
|
||||
object completed extends DateField(this)
|
||||
|
||||
|
||||
object label extends net.liftweb.record.field.StringField(this, 255)
|
||||
|
||||
|
||||
def formatDate(date : Date) : String = {
|
||||
OBPDetails.formats.dateFormat.format(date)
|
||||
}
|
||||
|
||||
|
||||
def whenAddedJson : JObject = {
|
||||
JObject(List( JField("type_en", JString(type_en.get)),
|
||||
JField("type_de", JString(type_de.get)),
|
||||
@ -466,8 +531,8 @@ object OBPDetails extends OBPDetails with BsonMetaRecord[OBPDetails]
|
||||
class OBPBalance private() extends BsonRecord[OBPBalance]{
|
||||
def meta = OBPBalance
|
||||
|
||||
object currency extends net.liftweb.record.field.StringField(this, 5)
|
||||
object amount extends net.liftweb.record.field.DecimalField(this, 0) // ok to use decimal?
|
||||
object currency extends StringField(this, 5)
|
||||
object amount extends DecimalField(this, 0) // ok to use decimal?
|
||||
|
||||
def whenAddedJson : JObject = {
|
||||
JObject(List( JField("currency", JString(currency.get)),
|
||||
@ -482,7 +547,7 @@ class OBPValue private() extends BsonRecord[OBPValue]{
|
||||
|
||||
object currency extends net.liftweb.record.field.StringField(this, 5)
|
||||
object amount extends net.liftweb.record.field.DecimalField(this, 0) // ok to use decimal?
|
||||
|
||||
|
||||
def whenAddedJson : JObject = {
|
||||
JObject(List( JField("currency", JString(currency.get)),
|
||||
JField("amount", JString(amount.get.toString))))
|
||||
@ -491,4 +556,62 @@ class OBPValue private() extends BsonRecord[OBPValue]{
|
||||
|
||||
object OBPValue extends OBPValue with BsonMetaRecord[OBPValue]
|
||||
|
||||
class OBPTag private() extends MongoRecord[OBPTag] with ObjectIdPk[OBPTag] with Tag {
|
||||
def meta = OBPTag
|
||||
object userId extends StringField(this,255)
|
||||
object viewID extends LongField(this)
|
||||
object tag extends StringField(this, 255)
|
||||
object date extends DateField(this)
|
||||
|
||||
def id_ = id.is.toString
|
||||
def datePosted = date.get
|
||||
def postedBy = User.findById(userId.get)
|
||||
def viewId = viewID.get
|
||||
def value = tag.get
|
||||
}
|
||||
|
||||
object OBPTag extends OBPTag with MongoMetaRecord[OBPTag]
|
||||
|
||||
class OBPTransactionImage private() extends MongoRecord[OBPTransactionImage]
|
||||
with ObjectIdPk[OBPTransactionImage] with TransactionImage {
|
||||
def meta = OBPTransactionImage
|
||||
|
||||
object userId extends StringField(this,255)
|
||||
object viewID extends LongField(this)
|
||||
object imageComment extends StringField(this, 1000)
|
||||
object date extends DateField(this)
|
||||
object url extends StringField(this, 500)
|
||||
|
||||
def id_ = id.is.toString
|
||||
def datePosted = date.get
|
||||
def postedBy = User.findById(userId.get)
|
||||
def viewId = viewID.get
|
||||
def description = imageComment.get
|
||||
def imageUrl = {
|
||||
tryo {new URL(url.get)} getOrElse OBPTransactionImage.notFoundUrl
|
||||
}
|
||||
}
|
||||
|
||||
object OBPTransactionImage extends OBPTransactionImage with MongoMetaRecord[OBPTransactionImage] {
|
||||
val notFoundUrl = new URL(S.hostAndPath + "/notfound.png") //TODO: Make this image exist?
|
||||
}
|
||||
|
||||
|
||||
class OBPGeoTag private() extends BsonRecord[OBPGeoTag] with GeoTag {
|
||||
def meta = OBPGeoTag
|
||||
|
||||
object userId extends StringField(this,255)
|
||||
object viewID extends LongField(this)
|
||||
object date extends DateField(this)
|
||||
|
||||
object geoLongitude extends DoubleField(this,0)
|
||||
object geoLatitude extends DoubleField(this,0)
|
||||
|
||||
def datePosted = date.get
|
||||
def postedBy = User.findById(userId.get)
|
||||
def viewId = viewID.get
|
||||
def longitude = geoLongitude.get
|
||||
def latitude = geoLatitude.get
|
||||
|
||||
}
|
||||
object OBPGeoTag extends OBPGeoTag with BsonMetaRecord[OBPGeoTag]
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -37,11 +37,9 @@ import net.liftweb.common._
|
||||
import net.liftweb.record.field.StringField
|
||||
import scala.xml.NodeSeq
|
||||
import net.liftweb.sitemap.Loc.LocGroup
|
||||
import net.liftweb.http.S
|
||||
import net.liftweb.http.SessionVar
|
||||
import net.liftweb.http.{S,SessionVar,Templates}
|
||||
import com.mongodb.QueryBuilder
|
||||
import code.model.traits.{View,BankAccount,User}
|
||||
import code.model.implementedTraits._
|
||||
import code.model.{View,User, BankAccount, OurNetwork, Management, Public, Team, Board, Authorities, Owner}
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.http.SHtml
|
||||
import net.liftweb.http.S
|
||||
@ -56,135 +54,51 @@ import net.liftweb.json.JsonAST.JObject
|
||||
*/
|
||||
class OBPUser extends MegaProtoUser[OBPUser] with User{
|
||||
def getSingleton = OBPUser // what's the "meta" server
|
||||
def id_ = id.is.toString
|
||||
def id_ = emailAddress
|
||||
def emailAddress = email.get
|
||||
def theFistName : String = firstName.get
|
||||
def theFirstName : String = firstName.get
|
||||
def theLastName : String = lastName.get
|
||||
def provider = Props.get("hostname","")
|
||||
|
||||
|
||||
def permittedViews(account: BankAccount): Set[View] = {
|
||||
var views: Set[View] = Set()
|
||||
if (OBPUser.hasOurNetworkPermission(account)) views = views + OurNetwork
|
||||
if (OBPUser.hasTeamPermission(account)) views = views + Team
|
||||
if (OBPUser.hasBoardPermission(account)) views = views + Board
|
||||
if (OBPUser.hasAuthoritiesPermission(account)) views = views + Authorities
|
||||
if (OBPUser.hasOwnerPermission(account)) views = views + Owner
|
||||
if (account.allowAnnoymousAccess) views = views + Anonymous
|
||||
if (hasOurNetworkPermission(account)) views = views + OurNetwork
|
||||
if (hasTeamPermission(account)) views = views + Team
|
||||
if (hasBoardPermission(account)) views = views + Board
|
||||
if (hasAuthoritiesPermission(account)) views = views + Authorities
|
||||
if (hasOwnerPermission(account)) views = views + Owner
|
||||
if (account.allowPublicAccess) views = views + Public
|
||||
views
|
||||
}
|
||||
|
||||
|
||||
def hasMangementAccess(bankAccount: BankAccount) = {
|
||||
OBPUser.hasManagementPermission(bankAccount)
|
||||
hasManagementPermission(bankAccount)
|
||||
}
|
||||
|
||||
def accountsWithMoreThanAnonAccess : Set[BankAccount] = {
|
||||
|
||||
val hostedAccountTable = HostedAccount._dbTableNameLC
|
||||
val privilegeTable = Privilege._dbTableNameLC
|
||||
val userTable = OBPUser._dbTableNameLC
|
||||
|
||||
val hostedId = hostedAccountTable + "." + HostedAccount.id.dbColumnName
|
||||
val hostedAccId = hostedAccountTable + "." + HostedAccount.accountID.dbColumnName
|
||||
val privilegeAccId = privilegeTable + "." + Privilege.account.dbColumnName
|
||||
val privilegeUserId = privilegeTable + "." + Privilege.user.dbColumnName
|
||||
val userId = this.id.get
|
||||
|
||||
val ourNetworkPrivilege = privilegeTable + "." + Privilege.ourNetworkPermission.dbColumnName
|
||||
val teamPrivilege = privilegeTable + "." + Privilege.teamPermission.dbColumnName
|
||||
val boardPrivilege = privilegeTable + "." + Privilege.boardPermission.dbColumnName
|
||||
val authoritiesPrivilege = privilegeTable + "." + Privilege.authoritiesPermission.dbColumnName
|
||||
val ownerPrivilege = privilegeTable + "." + Privilege.ownerPermission.dbColumnName
|
||||
|
||||
val query = "SELECT " + hostedId + ", " + hostedAccId +
|
||||
" FROM " + hostedAccountTable + ", " + privilegeTable + ", " + userTable +
|
||||
" WHERE " + "( " + hostedId + " = " + privilegeAccId + ")" +
|
||||
" AND " + "( " + privilegeUserId + " = " + userId + ")" +
|
||||
" AND " + "( " + ourNetworkPrivilege + " = true" +
|
||||
" OR " + teamPrivilege + " = true" +
|
||||
" OR " + boardPrivilege + " = true" +
|
||||
" OR " + authoritiesPrivilege + " = true" +
|
||||
" OR " + ownerPrivilege + " = true)"
|
||||
|
||||
val moreThanAnon = HostedAccount.findAllByInsecureSql(query, IHaveValidatedThisSQL("everett", "nov. 15 2012"))
|
||||
val mongoIds = moreThanAnon.map(hAcc => new ObjectId(hAcc.accountID.get))
|
||||
|
||||
Account.findAll(mongoIds).map(Account.toBankAccount).toSet
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The singleton that has methods for accessing the database
|
||||
*/
|
||||
object OBPUser extends OBPUser with MetaMegaProtoUser[OBPUser]{
|
||||
|
||||
override def dbTableName = "users" // define the DB table name
|
||||
|
||||
override def screenWrap = Full(<lift:surround with="default" at="content">
|
||||
<lift:bind /></lift:surround>)
|
||||
// define the order fields will appear in forms and output
|
||||
override def fieldOrder = List(id, firstName, lastName, email,
|
||||
locale, timezone, password)
|
||||
|
||||
// comment this line out to require email validations
|
||||
override def skipEmailValidation = true
|
||||
|
||||
//Keep track of the referer on login
|
||||
object loginReferer extends SessionVar("/")
|
||||
//This is where the user gets redirected to after login
|
||||
override def homePage = {
|
||||
var ret = loginReferer.is
|
||||
loginReferer.remove()
|
||||
ret
|
||||
}
|
||||
|
||||
override def loginXhtml = {
|
||||
import net.liftweb.http.TemplateFinder
|
||||
import net.liftweb.http.js.JsCmds.Noop
|
||||
val loginXml = TemplateFinder.findAnyTemplate(List("templates-hidden","_login")).map({
|
||||
"form [action]" #> {S.uri} &
|
||||
"#loginText * " #> {S.??("log.in")} &
|
||||
"#emailAddressText * " #> {S.??("email.address")} &
|
||||
"#passwordText * " #> {S.??("password")} &
|
||||
"#recoverPasswordLink * " #> {
|
||||
"a [href]" #> {lostPasswordPath.mkString("/", "/", "")} &
|
||||
"a *" #> {S.??("recover.password")}
|
||||
} &
|
||||
"#SignUpLink * " #> {
|
||||
"a [href]" #> {OBPUser.signUpPath.foldLeft("")(_ + "/" + _)} &
|
||||
"a *" #> {S.??("sign.up")}
|
||||
}
|
||||
})
|
||||
SHtml.span(loginXml getOrElse NodeSeq.Empty,Noop)
|
||||
}
|
||||
|
||||
//Set the login referer
|
||||
override def login = {
|
||||
for(r <- S.referer if loginReferer.is.equals("/")) loginReferer.set(r)
|
||||
super.login
|
||||
}
|
||||
|
||||
def hasOurNetworkPermission(account: BankAccount) : Boolean = {
|
||||
hasPermission(account, (p: Privilege) => p.ourNetworkPermission.is)
|
||||
}
|
||||
|
||||
|
||||
def hasTeamPermission(account: BankAccount) : Boolean = {
|
||||
hasPermission(account, (p: Privilege) => p.teamPermission.is)
|
||||
}
|
||||
|
||||
|
||||
def hasBoardPermission(account: BankAccount) : Boolean = {
|
||||
hasPermission(account, (p: Privilege) => p.boardPermission.is)
|
||||
}
|
||||
|
||||
|
||||
def hasAuthoritiesPermission(account: BankAccount) : Boolean = {
|
||||
hasPermission(account, (p: Privilege) => p.authoritiesPermission.is)
|
||||
}
|
||||
|
||||
|
||||
def hasOwnerPermission(account: BankAccount) : Boolean = {
|
||||
hasPermission(account, (p: Privilege) => p.ownerPermission.is)
|
||||
}
|
||||
def hasManagementPermission(account: BankAccount) : Boolean = {
|
||||
hasPermission(account, (p: Privilege) => p.mangementPermission.is)
|
||||
}
|
||||
|
||||
|
||||
def hasMoreThanAnonAccess(account: BankAccount) : Boolean = {
|
||||
OBPUser.hasAuthoritiesPermission(account) ||
|
||||
OBPUser.hasBoardPermission(account) ||
|
||||
@ -193,23 +107,72 @@ object OBPUser extends OBPUser with MetaMegaProtoUser[OBPUser]{
|
||||
OBPUser.hasTeamPermission(account) ||
|
||||
OBPUser.hasManagementPermission(account)
|
||||
}
|
||||
|
||||
def hasPermission(bankAccount: BankAccount, permissionCheck: (Privilege) => Boolean) : Boolean = {
|
||||
currentUser match{
|
||||
case Full(u) =>
|
||||
HostedAccount.find(By(HostedAccount.accountID, bankAccount.id)) match {
|
||||
case Full(hostedAccount) =>
|
||||
Privilege.find(By(Privilege.account, hostedAccount), By(Privilege.user, u)) match{
|
||||
case Full(p) => permissionCheck(p)
|
||||
case _ => false
|
||||
}
|
||||
case _ => false
|
||||
|
||||
def hasPermission(bankAccount: BankAccount, permissionCheck: (Privilege) => Boolean): Boolean = {
|
||||
HostedAccount.find(By(HostedAccount.accountID, bankAccount.id)) match {
|
||||
case Full(hostedAccount) =>
|
||||
Privilege.find(By(Privilege.account, hostedAccount), By(Privilege.user, this)) match {
|
||||
case Full(p) => permissionCheck(p)
|
||||
case _ => false
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The singleton that has methods for accessing the database
|
||||
*/
|
||||
object OBPUser extends OBPUser with MetaMegaProtoUser[OBPUser]{
|
||||
|
||||
override def dbTableName = "users" // define the DB table name
|
||||
|
||||
override def screenWrap = Full(<lift:surround with="default" at="content">
|
||||
<lift:bind /></lift:surround>)
|
||||
// define the order fields will appear in forms and output
|
||||
override def fieldOrder = List(id, firstName, lastName, email,
|
||||
locale, timezone, password)
|
||||
|
||||
// comment this line out to require email validations
|
||||
override def skipEmailValidation = true
|
||||
|
||||
//Keep track of the referer on login
|
||||
object loginReferer extends SessionVar("/")
|
||||
//This is where the user gets redirected to after login
|
||||
override def homePage = {
|
||||
var ret = loginReferer.is
|
||||
loginReferer.remove()
|
||||
ret
|
||||
}
|
||||
|
||||
override def loginXhtml = {
|
||||
import net.liftweb.http.TemplateFinder
|
||||
import net.liftweb.http.js.JsCmds.Noop
|
||||
val loginXml = Templates(List("templates-hidden","_UserLogin")).map({
|
||||
"form [action]" #> {S.uri} &
|
||||
"#loginText * " #> {S.??("log.in")} &
|
||||
"#emailAddressText * " #> {S.??("email.address")} &
|
||||
"#passwordText * " #> {S.??("password")} &
|
||||
"#recoverPasswordLink * " #> {
|
||||
"a [href]" #> {lostPasswordPath.mkString("/", "/", "")} &
|
||||
"a *" #> {S.??("recover.password")}
|
||||
} &
|
||||
"#SignUpLink * " #> {
|
||||
"a [href]" #> {OBPUser.signUpPath.foldLeft("")(_ + "/" + _)} &
|
||||
"a *" #> {S.??("sign.up")}
|
||||
}
|
||||
})
|
||||
SHtml.span(loginXml getOrElse NodeSeq.Empty,Noop)
|
||||
}
|
||||
|
||||
//Set the login referer
|
||||
override def login = {
|
||||
for(r <- S.referer if loginReferer.is.equals("/")) loginReferer.set(r)
|
||||
super.login
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Yes, MappedBoolean has a default value of false, but in the very small chance
|
||||
* that this changes, we won't break any authentication.
|
||||
@ -221,14 +184,14 @@ class ourMappedBoolean[T<:Mapper[T]](fieldOwner: T) extends MappedBoolean[T](fie
|
||||
class Privilege extends LongKeyedMapper[Privilege] with CreatedUpdated{
|
||||
def getSingleton = Privilege
|
||||
def primaryKeyField = id
|
||||
object id extends MappedLongIndex(this)
|
||||
object id extends MappedLongIndex(this)
|
||||
object user extends MappedLongForeignKey(this, OBPUser){
|
||||
var userError = false
|
||||
override def validSelectValues =
|
||||
Full(OBPUser.findMap(OrderBy(OBPUser.email, Ascending)){
|
||||
case u: User => Full(u.id.is -> u.email.is)
|
||||
})
|
||||
override def displayHtml = <span>User email</span>
|
||||
override def displayHtml = <span>User email</span>
|
||||
override def asHtml = {
|
||||
val email = (for {
|
||||
u <- OBPUser.find(user.get)
|
||||
@ -236,35 +199,35 @@ class Privilege extends LongKeyedMapper[Privilege] with CreatedUpdated{
|
||||
|
||||
<span>{email}</span>
|
||||
}
|
||||
def userEmailCheck(user : Long) : List[FieldError]=
|
||||
if(userError) List(FieldError(this, "No user with this email"))
|
||||
def userEmailCheck(user : Long) : List[FieldError]=
|
||||
if(userError) List(FieldError(this, "No user with this email"))
|
||||
else Nil
|
||||
override def validations = userEmailCheck _ :: super.validations
|
||||
override def _toForm =
|
||||
{
|
||||
{
|
||||
val initialValue = user.obj match {
|
||||
case Full(theUser) => theUser.email.is
|
||||
case _ => ""
|
||||
case _ => ""
|
||||
}
|
||||
def saveTheUser(email : String) =
|
||||
def saveTheUser(email : String) =
|
||||
OBPUser.find(By(OBPUser.email, email)) match {
|
||||
case Full(theUser) => user(theUser)
|
||||
case _ => userError=true
|
||||
}
|
||||
}
|
||||
Full(SHtml.text(initialValue, saveTheUser(_)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object account extends MappedLongForeignKey(this, HostedAccount){
|
||||
|
||||
override def displayHtml = <span>Account</span>
|
||||
|
||||
override def displayHtml = <span>Account</span>
|
||||
override def asHtml = {
|
||||
<span>{
|
||||
HostedAccount.find(account.get) match {
|
||||
case Full(account) => account.bank + " - " + account.name
|
||||
case _ => "account not found"
|
||||
}
|
||||
}</span>
|
||||
}</span>
|
||||
}
|
||||
override def validSelectValues =
|
||||
Full(
|
||||
@ -275,7 +238,7 @@ class Privilege extends LongKeyedMapper[Privilege] with CreatedUpdated{
|
||||
case privilege: Privilege => HostedAccount.find(privilege.account.is) match {
|
||||
case Full(hosted) => Full(hosted.id.is -> (hosted.bank + " - "+ hosted.name + " - " + hosted.number) )
|
||||
case _ => Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
case _ => List()
|
||||
}
|
||||
@ -305,22 +268,22 @@ class Privilege extends LongKeyedMapper[Privilege] with CreatedUpdated{
|
||||
object Privilege extends Privilege with LongKeyedMetaMapper[Privilege] with CRUDify[Long, Privilege]{
|
||||
override def calcPrefix = List("admin",_dbTableNameLC)
|
||||
override def fieldOrder = List(account, user,updatedAt, ownerPermission, mangementPermission,
|
||||
ourNetworkPermission, teamPermission, boardPermission)
|
||||
ourNetworkPermission, teamPermission, boardPermission)
|
||||
override def displayName = "Privilege"
|
||||
override def showAllMenuLocParams = LocGroup("admin") :: Nil
|
||||
override def createMenuLocParams = LocGroup("admin") :: Nil
|
||||
override def fieldsForDisplay = super.fieldsForDisplay -- List(createdAt)
|
||||
override def fieldsForEditing = super.fieldsForEditing -- List(createdAt, updatedAt)
|
||||
override def fieldsForDisplay = super.fieldsForDisplay filterNot (List(createdAt) contains)
|
||||
override def fieldsForEditing = super.fieldsForEditing filterNot (List(createdAt, updatedAt) contains)
|
||||
def showAll = doCrudAll(_)
|
||||
override def findForList(start : Long, count : Int)= {
|
||||
OBPUser.currentUser match {
|
||||
case Full(user) => {
|
||||
def ownerPermissionTest(privilege : Privilege) : Boolean =
|
||||
def ownerPermissionTest(privilege : Privilege) : Boolean =
|
||||
Privilege.find(By(Privilege.user, user), By(Privilege.account, privilege.account)) match {
|
||||
case Full(currentUserPrivilege) => currentUserPrivilege.ownerPermission
|
||||
case _ => false
|
||||
case _ => false
|
||||
}
|
||||
//we show only the privileges that concernes accounts were the current user
|
||||
//we show only the privileges that concernes accounts were the current user
|
||||
//has owner permissions on
|
||||
//TODO: This is inefficient (it loads all privileges)
|
||||
Privilege.findAll(OrderBy(Privilege.account, Ascending)).filter(ownerPermissionTest _)
|
||||
@ -332,15 +295,15 @@ object Privilege extends Privilege with LongKeyedMetaMapper[Privilege] with CRUD
|
||||
class HostedAccount extends LongKeyedMapper[HostedAccount] {
|
||||
def getSingleton = HostedAccount
|
||||
def primaryKeyField = id
|
||||
|
||||
object id extends MappedLongIndex(this)
|
||||
|
||||
object id extends MappedLongIndex(this)
|
||||
object accountID extends MappedString(this, 255)
|
||||
|
||||
def theAccount = Account.find(("_id", accountID.toString))
|
||||
|
||||
def name : String= theAccount match {
|
||||
case Full(account) => account.name.get.toString()
|
||||
case _ => ""
|
||||
case _ => ""
|
||||
}
|
||||
def bank : String = theAccount match {
|
||||
case Full(account) => account.bankName
|
||||
@ -349,7 +312,7 @@ class HostedAccount extends LongKeyedMapper[HostedAccount] {
|
||||
def number : String = theAccount match {
|
||||
case Full(account) => account.number.get
|
||||
case _ => ""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
object HostedAccount extends HostedAccount with LongKeyedMetaMapper[HostedAccount]{}
|
||||
|
||||
@ -29,18 +29,17 @@ Berlin 13359, Germany
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.dataAccess
|
||||
|
||||
package code.model.traits
|
||||
import net.liftweb.mongodb.record.field.{ObjectIdPk,DateField}
|
||||
import net.liftweb.record.field.{StringField}
|
||||
import net.liftweb.mongodb.record.{MongoRecord,MongoMetaRecord}
|
||||
|
||||
trait OtherBankAccount {
|
||||
|
||||
def id : String
|
||||
//account holder hame
|
||||
def label : String
|
||||
def nationalIdentifier : String
|
||||
def bankName : String
|
||||
def number : String
|
||||
def swift_bic : Option[String]
|
||||
def iban : Option[String]
|
||||
def metadata : OtherBankAccountMetadata
|
||||
class APIMetric extends MongoRecord[APIMetric] with ObjectIdPk[APIMetric] {
|
||||
def meta = APIMetric
|
||||
object url extends StringField(this,255)
|
||||
object date extends DateField(this)
|
||||
}
|
||||
|
||||
object APIMetric extends APIMetric with MongoMetaRecord[APIMetric]
|
||||
@ -1,124 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.model.implementedTraits
|
||||
|
||||
import scala.math.BigDecimal
|
||||
import java.util.Date
|
||||
import scala.collection.immutable.Set
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.common.Full
|
||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException
|
||||
import code.model.traits.{BankAccount,AccountOwner, Transaction}
|
||||
import code.model.dataAccess.{Account,OBPEnvelope}
|
||||
import code.model.traits.Transaction
|
||||
import code.model.traits.ModeratedTransaction
|
||||
import code.model.dataAccess.OBPEnvelope.OBPQueryParam
|
||||
import net.liftweb.common.Box
|
||||
import code.model.dataAccess.LocalStorage
|
||||
import code.model.dataAccess.OBPEnvelope._
|
||||
import code.model.dataAccess.OBPUser
|
||||
import code.model.traits.User
|
||||
|
||||
class BankAccountImpl(id_ : String, var _owners : Set[AccountOwner], accountType_ : String,
|
||||
currency_ : String, label_ : String, nationalIdentifier_ : String, swift_bic_ : Option[String],
|
||||
iban_ : Option[String], allowAnnoymousAccess_ : Boolean,
|
||||
number_ : String, bankName_ : String, bankPermalink_ : String, permalink_ : String) extends BankAccount {
|
||||
|
||||
def id = id_
|
||||
def owners = _owners
|
||||
def owners_=(owners_ : Set[AccountOwner]) = _owners = owners_
|
||||
def accountType = accountType_
|
||||
def balance = {
|
||||
val newest = getTransactions(OBPLimit(1), OBPOrdering(None, OBPDescending))
|
||||
newest match {
|
||||
case Full(n) => {
|
||||
n match {
|
||||
case Nil => None
|
||||
case x :: xs => Some(x.balance)
|
||||
}
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
def bankPermalink = bankPermalink_
|
||||
def permalink = permalink_
|
||||
def currency = currency_
|
||||
def label = label_
|
||||
def nationalIdentifier = nationalIdentifier_
|
||||
def swift_bic = swift_bic_
|
||||
def iban = iban_
|
||||
def number = number_
|
||||
def bankName = bankName_
|
||||
|
||||
def permittedViews(user: Box[User]) : Set[code.model.traits.View] = {
|
||||
user match {
|
||||
case Full(u) => u.permittedViews(this)
|
||||
case _ => if(this.allowAnnoymousAccess) Set(Anonymous) else Set()
|
||||
}
|
||||
}
|
||||
|
||||
def transactions(from: Date, to: Date): Set[Transaction] = {
|
||||
throw new NotImplementedException
|
||||
}
|
||||
def transaction(id: String): Box[Transaction] = {
|
||||
LocalStorage.getTransaction(id, bankPermalink, permalink)
|
||||
}
|
||||
def allowAnnoymousAccess = allowAnnoymousAccess_
|
||||
|
||||
def getModeratedTransactions(moderate: Transaction => ModeratedTransaction): List[ModeratedTransaction] = {
|
||||
LocalStorage.getModeratedTransactions(permalink, bankPermalink)(moderate)
|
||||
}
|
||||
|
||||
def getModeratedTransactions(queryParams: OBPQueryParam*)(moderate: Transaction => ModeratedTransaction): List[ModeratedTransaction] = {
|
||||
LocalStorage.getModeratedTransactions(permalink, bankPermalink, queryParams: _*)(moderate)
|
||||
}
|
||||
|
||||
def getTransactions(queryParams: OBPQueryParam*) : Box[List[Transaction]] = {
|
||||
LocalStorage.getTransactions(permalink, bankPermalink, queryParams: _*)
|
||||
}
|
||||
|
||||
def getTransactions(bank: String, account: String): Box[List[Transaction]] = {
|
||||
LocalStorage.getTransactions(permalink, bankPermalink)
|
||||
}
|
||||
|
||||
def authorisedAccess(view: code.model.traits.View, user: Option[OBPUser]) = {
|
||||
view match {
|
||||
case Anonymous => allowAnnoymousAccess
|
||||
case _ => user match {
|
||||
case Some(u) => u.permittedViews(this).contains(view)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.model.implementedTraits
|
||||
|
||||
import code.model.traits.{Bank, BankAccount}
|
||||
import code.model.dataAccess.LocalStorage
|
||||
|
||||
class BankImpl(_id: String, _name : String, _permalink : String) extends Bank
|
||||
{
|
||||
def id = _id
|
||||
def name = _name
|
||||
def permalink = _permalink
|
||||
def accounts = LocalStorage.getBankAccounts(this)
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.model.implementedTraits
|
||||
|
||||
import code.model.traits.{Comment, OtherBankAccountMetadata, TransactionMetadata}
|
||||
import code.model.dataAccess.{OtherAccount, OBPComment}
|
||||
import net.liftweb.common.Loggable
|
||||
import java.util.Date
|
||||
|
||||
class OtherBankAccountMetadataImpl(_publicAlias : String, _privateAlias : String,_moreInfo : String,
|
||||
_url : String, _imageUrl : String, _openCorporatesUrl : String) extends OtherBankAccountMetadata {
|
||||
|
||||
def publicAlias : String = _publicAlias
|
||||
def privateAlias : String = _privateAlias
|
||||
def moreInfo : String = _moreInfo
|
||||
def url : String = _url
|
||||
def imageUrl : String = _imageUrl
|
||||
def openCorporatesUrl : String = _openCorporatesUrl
|
||||
}
|
||||
class TransactionMetadataImpl(narative : String, comments_ : List[Comment],
|
||||
saveOwnerComment : String => Unit, addCommentFunc : (Long,Long, String, Date) => Unit )
|
||||
extends TransactionMetadata with Loggable
|
||||
{
|
||||
def ownerComment = if(! narative.isEmpty) Some(narative) else None
|
||||
def ownerComment(comment : String) = saveOwnerComment(comment)
|
||||
def comments : List[Comment] = comments_
|
||||
def addComment(userId: Long, viewId : Long, text: String, datePosted : Date) : Unit =
|
||||
addCommentFunc(userId, viewId, text, datePosted)
|
||||
}
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.model.implementedTraits
|
||||
|
||||
import code.model.traits.{OtherBankAccountMetadata,OtherBankAccount}
|
||||
|
||||
class OtherBankAccountImpl(id_ : String, label_ : String, nationalIdentifier_ : String,
|
||||
swift_bic_ : Option[String], iban_ : Option[String], number_ : String,
|
||||
bankName_ : String, metadata_ : OtherBankAccountMetadata) extends OtherBankAccount
|
||||
{
|
||||
|
||||
def id = id_
|
||||
def label = label_
|
||||
def nationalIdentifier = nationalIdentifier_
|
||||
def swift_bic = swift_bic_
|
||||
def iban = iban_
|
||||
def number = number_
|
||||
def bankName = bankName_
|
||||
def metadata = metadata_
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.model.implementedTraits
|
||||
|
||||
import code.model.dataAccess.{OBPEnvelope,OBPTransaction,OtherAccount}
|
||||
import code.model.traits.{Transaction,BankAccount,OtherBankAccount, TransactionMetadata}
|
||||
import scala.math.BigDecimal
|
||||
import java.util.Date
|
||||
import scala.collection.immutable.List
|
||||
import net.liftweb.common.Loggable
|
||||
import net.liftweb.common.Box
|
||||
import code.model.traits.Comment
|
||||
|
||||
class TransactionImpl(id_ : String, var _thisAccount : BankAccount = null, otherAccount_ : OtherBankAccount,
|
||||
metadata_ : TransactionMetadata, transactionType_ : String, amount_ : BigDecimal, currency_ : String,
|
||||
label_ : Option[String], startDate_ : Date, finishDate_ : Date, balance_ : BigDecimal) extends Transaction with Loggable {
|
||||
|
||||
def id = id_
|
||||
def thisAccount = _thisAccount
|
||||
def thisAccount_= (newThisAccount : BankAccount) = _thisAccount = newThisAccount
|
||||
def otherAccount = otherAccount_
|
||||
def metadata = metadata_
|
||||
def transactionType = transactionType_
|
||||
def amount = amount_
|
||||
def currency = currency_
|
||||
def label = label_
|
||||
def startDate = startDate_
|
||||
def finishDate = finishDate_
|
||||
def balance = balance_
|
||||
}
|
||||
@ -1,223 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.implementedTraits
|
||||
|
||||
import code.model.traits._
|
||||
import net.liftweb.common.{Box,Empty, Full}
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
|
||||
object View {
|
||||
//transforme the url into a view
|
||||
//TODO : load the view from the Data base
|
||||
def fromUrl(viewNameURL: String): Box[View] =
|
||||
viewNameURL match {
|
||||
case "authorities" => Full(Authorities)
|
||||
case "board" => Full(Board)
|
||||
case "our-network" => Full(OurNetwork)
|
||||
case "team" => Full(Team)
|
||||
case "owner" => Full(Owner)
|
||||
case "anonymous" => Full(Anonymous)
|
||||
case _ => Empty
|
||||
}
|
||||
|
||||
def linksJson(views: Set[View], accountPermalink: String, bankPermalink: String): JObject = {
|
||||
val viewsJson = views.map(view => {
|
||||
("rel" -> "account") ~
|
||||
("href" -> { "/" + bankPermalink + "/account/" + accountPermalink + "/" + view.permalink }) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> "Get information about one account")
|
||||
})
|
||||
|
||||
("links" -> viewsJson)
|
||||
}
|
||||
}
|
||||
object Team extends FullView {
|
||||
override def id = 3
|
||||
override def name = "Team"
|
||||
override def permalink = "team"
|
||||
override def description = "A view for team members related to the account. E.g. for a company bank account -> employees/contractors"
|
||||
override def canEditOwnerComment= false
|
||||
}
|
||||
object Board extends FullView {
|
||||
override def id = 4
|
||||
override def name = "Board"
|
||||
override def permalink = "board"
|
||||
override def description = "A view for board members of a company to view that company's account data."
|
||||
override def canEditOwnerComment= false
|
||||
}
|
||||
object Authorities extends FullView {
|
||||
override def id = 5
|
||||
override def name = "Authorities"
|
||||
override def permalink = "authorities"
|
||||
override def description = "A view for authorities such as tax officials to view an account's data"
|
||||
override def canEditOwnerComment= false
|
||||
}
|
||||
|
||||
object Anonymous extends BaseView {
|
||||
//the actual class extends the BaseView but in fact it does not matters be cause we don't care about the values
|
||||
//of the canSeeMoreInfo, canSeeUrl,etc attributes and we implement a specific moderate method
|
||||
|
||||
/**
|
||||
* Current rules:
|
||||
*
|
||||
* If anonymous, and a public alias exists : Show the public alias
|
||||
* If anonymous, and no public alias exists : Show the real account holder
|
||||
* If our network, and a private alias exists : Show the private alias
|
||||
* If our network, and no private alias exists : Show the real account holder
|
||||
*/
|
||||
override def id = 6
|
||||
override def name = "Anonymous"
|
||||
override def permalink = "anonymous"
|
||||
override def description = "A view of the account accessible by anyone."
|
||||
|
||||
//Bank account fields
|
||||
override def canSeeBankAccountOwners = true
|
||||
override def canSeeBankAccountType = true
|
||||
override def canSeeBankAccountBalancePositiveOrNegative = true
|
||||
override def canSeeBankAccountCurrency = true
|
||||
override def canSeeBankAccountLabel = true
|
||||
override def canSeeBankAccountNationalIdentifier = true
|
||||
override def canSeeBankAccountSwift_bic = true
|
||||
override def canSeeBankAccountIban = true
|
||||
override def canSeeBankAccountNumber = true
|
||||
override def canSeeBankAccountName = true
|
||||
|
||||
override def moderate(transaction: Transaction): ModeratedTransaction = {
|
||||
|
||||
val transactionId = transaction.id //toString().startsWith("-")) "-" else "+"
|
||||
val accountBalance = "" //not used when displaying transactions, but we might eventually need it. if so, we need a ref to
|
||||
//the bank account so we could do something like if(canSeeBankAccountBalance) bankAccount.balance else if
|
||||
// canSeeBankAccountBalancePositiveOrNegative {show + or -} else ""
|
||||
val thisBankAccount = Some(new ModeratedBankAccount(transaction.thisAccount.id,
|
||||
Some(transaction.thisAccount.owners), Some(transaction.thisAccount.accountType),
|
||||
accountBalance, Some(transaction.thisAccount.currency),
|
||||
Some(transaction.thisAccount.label),None, None, None, Some(transaction.thisAccount.number),
|
||||
Some(transaction.thisAccount.bankName)))
|
||||
val otherBankAccount = {
|
||||
val otherAccountLabel = {
|
||||
val publicAlias = transaction.otherAccount.metadata.publicAlias
|
||||
if(publicAlias.isEmpty)
|
||||
AccountName(transaction.otherAccount.label, NoAlias)
|
||||
else
|
||||
AccountName(publicAlias, Public)
|
||||
}
|
||||
val otherAccountMetadata = {
|
||||
def isPublicAlias = otherAccountLabel.aliasType match {
|
||||
case Public => true
|
||||
case _ => false
|
||||
}
|
||||
val moreInfo = if (isPublicAlias) None else Some(transaction.otherAccount.metadata.moreInfo)
|
||||
val url = if (isPublicAlias) None else Some(transaction.otherAccount.metadata.url)
|
||||
val imageUrl = if (isPublicAlias) None else Some(transaction.otherAccount.metadata.imageUrl)
|
||||
val openCorporatesUrl = if (isPublicAlias) None else Some(transaction.otherAccount.metadata.openCorporatesUrl)
|
||||
|
||||
Some(new ModeratedOtherBankAccountMetadata(moreInfo, url, imageUrl, openCorporatesUrl))
|
||||
}
|
||||
|
||||
Some(new ModeratedOtherBankAccount(transaction.otherAccount.id,otherAccountLabel,None,None,
|
||||
None, None, None, otherAccountMetadata))
|
||||
}
|
||||
val transactionMetadata = Some(new ModeratedTransactionMetadata(
|
||||
transaction.metadata.ownerComment,Some(transaction.metadata.comments.filter(comment => comment.viewId==id)),
|
||||
None,Some(transaction.metadata.addComment _)))
|
||||
val transactionType = Some(transaction.transactionType)
|
||||
val transactionAmount = Some(transaction.amount)
|
||||
val transactionCurrency = Some(transaction.currency)
|
||||
val transactionLabel = Some(transaction.label)
|
||||
val transactionStartDate = Some(transaction.startDate)
|
||||
val transactionFinishDate = Some(transaction.finishDate)
|
||||
val transactionBalance = if (transaction.balance.toString().startsWith("-")) "-" else "+"
|
||||
|
||||
new ModeratedTransaction(transactionId, thisBankAccount, otherBankAccount, transactionMetadata,
|
||||
transactionType, transactionAmount, transactionCurrency, transactionLabel, transactionStartDate,
|
||||
transactionFinishDate, transactionBalance)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object OurNetwork extends BaseView
|
||||
{
|
||||
override def id = 7
|
||||
override def name = "Our Network"
|
||||
override def permalink ="our-network"
|
||||
override def description = "A view for people related to the account in some way. E.g. for a company account this could include investors" +
|
||||
" or current/potential clients"
|
||||
override def moderate(transaction: Transaction): ModeratedTransaction = {
|
||||
val transactionId = transaction.id
|
||||
val accountBalance = "" //not used when displaying transactions, but we might eventually need it. if so, we need a ref to
|
||||
//the bank account so we could do something like if(canSeeBankAccountBalance) bankAccount.balance else if
|
||||
// canSeeBankAccountBalancePositiveOrNegative {show + or -} else ""
|
||||
val thisBankAccount = Some(new ModeratedBankAccount(transaction.thisAccount.id, None, None,
|
||||
accountBalance, Some(transaction.thisAccount.currency),
|
||||
Some(transaction.thisAccount.label),None, None, None, Some(transaction.thisAccount.number),
|
||||
Some(transaction.thisAccount.bankName)))
|
||||
val otherBankAccount = {
|
||||
val otherAccountLabel = {
|
||||
val privateAlias = transaction.otherAccount.metadata.privateAlias
|
||||
if(privateAlias.isEmpty)
|
||||
AccountName(transaction.otherAccount.label, NoAlias)
|
||||
else
|
||||
AccountName(privateAlias, Private)
|
||||
}
|
||||
val otherAccountMetadata =
|
||||
Some(new ModeratedOtherBankAccountMetadata(Some(transaction.otherAccount.metadata.moreInfo),
|
||||
Some(transaction.otherAccount.metadata.url), Some(transaction.otherAccount.metadata.imageUrl),
|
||||
Some(transaction.otherAccount.metadata.openCorporatesUrl)))
|
||||
|
||||
Some(new ModeratedOtherBankAccount(transaction.otherAccount.id,otherAccountLabel,None,None,None,
|
||||
None, None, otherAccountMetadata))
|
||||
}
|
||||
val transactionMetadata = Some(new ModeratedTransactionMetadata(transaction.metadata.ownerComment,
|
||||
Some(transaction.metadata.comments.filter(comment => comment.viewId==id)),None,Some(transaction.metadata.addComment _)))
|
||||
|
||||
val transactionType = Some(transaction.transactionType)
|
||||
val transactionAmount = Some(transaction.amount)
|
||||
val transactionCurrency = Some(transaction.currency)
|
||||
val transactionLabel = Some(transaction.label)
|
||||
val transactionStartDate = Some(transaction.startDate)
|
||||
val transactionFinishDate = Some(transaction.finishDate)
|
||||
val transactionBalance = transaction.balance.toString()
|
||||
|
||||
new ModeratedTransaction(transactionId, thisBankAccount, otherBankAccount, transactionMetadata,
|
||||
transactionType, transactionAmount, transactionCurrency, transactionLabel, transactionStartDate,
|
||||
transactionFinishDate, transactionBalance)
|
||||
}
|
||||
}
|
||||
|
||||
object Owner extends FullView {
|
||||
override def id = 8
|
||||
override def name="Owner"
|
||||
override def permalink = "owner"
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.traits
|
||||
|
||||
trait AccountOwner {
|
||||
|
||||
def id : String
|
||||
|
||||
def name : String
|
||||
|
||||
def bankAccounts : Set[BankAccount]
|
||||
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.traits
|
||||
import net.liftweb.common.Box
|
||||
import code.model.dataAccess.LocalStorage
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.JsonAST.JArray
|
||||
|
||||
trait Bank
|
||||
{
|
||||
def id : String
|
||||
def name : String
|
||||
def permalink : String
|
||||
def accounts : Set[BankAccount]
|
||||
|
||||
def detailedJson : JObject = {
|
||||
("name" -> name) ~
|
||||
("website" -> "") ~
|
||||
("email" -> "")
|
||||
}
|
||||
|
||||
def toJson : JObject = {
|
||||
("alias" -> permalink) ~
|
||||
("name" -> name) ~
|
||||
("logo" -> "") ~
|
||||
("links" -> linkJson)
|
||||
}
|
||||
|
||||
def linkJson : JObject = {
|
||||
("rel" -> "bank") ~
|
||||
("href" -> {"/" + permalink + "/bank"}) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> {"Get information about the bank identified by " + permalink})
|
||||
}
|
||||
}
|
||||
|
||||
object Bank {
|
||||
def apply(bankPermalink: String) : Box[Bank] = LocalStorage.getBank(bankPermalink)
|
||||
|
||||
def all : List[Bank] = LocalStorage.allBanks
|
||||
|
||||
def toJson(banks: Seq[Bank]) : JArray =
|
||||
banks.map(bank => bank.toJson)
|
||||
|
||||
}
|
||||
@ -1,131 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.traits
|
||||
import scala.math.BigDecimal
|
||||
import java.util.Date
|
||||
import net.liftweb.common.Box
|
||||
import code.model.dataAccess.LocalStorage
|
||||
import net.liftweb.common.{Full, Empty}
|
||||
import code.model.dataAccess.Account
|
||||
import code.model.dataAccess.OBPEnvelope.OBPQueryParam
|
||||
import code.model.dataAccess.OBPUser
|
||||
import net.liftweb.json.JObject
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.http.LiftResponse
|
||||
import net.liftweb.http.JsonResponse
|
||||
import code.model.implementedTraits.View
|
||||
|
||||
trait BankAccount {
|
||||
|
||||
def id : String
|
||||
|
||||
var owners : Set[AccountOwner]
|
||||
|
||||
//e.g. chequing, savings
|
||||
def accountType : String
|
||||
|
||||
//TODO: Check if BigDecimal is an appropriate data type
|
||||
def balance : Option[BigDecimal]
|
||||
|
||||
//ISO 4217, e.g. EUR, GBP, USD, etc.
|
||||
def currency: String
|
||||
|
||||
//Name to display, e.g. TESOBE Postbank Account
|
||||
def label : String
|
||||
|
||||
def bankName : String
|
||||
|
||||
def bankPermalink : String
|
||||
|
||||
def permalink : String
|
||||
|
||||
def number: String
|
||||
|
||||
def nationalIdentifier : String
|
||||
|
||||
def swift_bic : Option[String]
|
||||
|
||||
def iban : Option[String]
|
||||
|
||||
def transaction(id: String) : Box[Transaction]
|
||||
|
||||
def moderatedTransaction(id: String, view: View, user: Box[User]) : Box[ModeratedTransaction] = {
|
||||
if(permittedViews(user).contains(view)) {
|
||||
transaction(id).map(view.moderate)
|
||||
} else Empty
|
||||
}
|
||||
|
||||
def moderatedBankAccount(view: View, user: Box[User]) : Box[ModeratedBankAccount] = {
|
||||
if(permittedViews(user).contains(view)){
|
||||
view.moderate(this)
|
||||
} else Empty
|
||||
}
|
||||
|
||||
//Is an anonymous view available for this bank account
|
||||
def allowAnnoymousAccess : Boolean
|
||||
|
||||
def permittedViews(user: Box[User]) : Set[View]
|
||||
|
||||
def getModeratedTransactions(moderate: Transaction => ModeratedTransaction): List[ModeratedTransaction]
|
||||
|
||||
def getModeratedTransactions(queryParams: OBPQueryParam*)(moderate: Transaction => ModeratedTransaction): List[ModeratedTransaction]
|
||||
|
||||
def authorisedAccess(view: View, user: Option[OBPUser]) : Boolean
|
||||
|
||||
def overviewJson(user: Box[User]): JObject = {
|
||||
val views = permittedViews(user)
|
||||
("number" -> number) ~
|
||||
("account_alias" -> label) ~
|
||||
("owner_description" -> "") ~
|
||||
("views_available" -> views.map(view => view.toJson)) ~
|
||||
View.linksJson(views, permalink, bankPermalink)
|
||||
}
|
||||
}
|
||||
|
||||
object BankAccount {
|
||||
def apply(bankpermalink: String, bankAccountPermalink: String) : Box[BankAccount] = {
|
||||
LocalStorage.getAccount(bankpermalink, bankAccountPermalink) match {
|
||||
case Full(account) => Full(Account.toBankAccount(account))
|
||||
case _ => Empty
|
||||
}
|
||||
}
|
||||
|
||||
def all : List[BankAccount] = {
|
||||
LocalStorage.getAllAccounts() map Account.toBankAccount
|
||||
}
|
||||
|
||||
def publicAccounts : List[BankAccount] = {
|
||||
LocalStorage.getAllPublicAccounts() map Account.toBankAccount
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.traits
|
||||
import java.util.Date
|
||||
import net.liftweb.common.{Box,Full}
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
import net.liftweb.json.JsonDSL._
|
||||
|
||||
trait Comment {
|
||||
def id_ : String
|
||||
// The person that posted the comment
|
||||
def postedBy : Box[User]
|
||||
|
||||
//the id of the view related to the comment
|
||||
def viewId : Long
|
||||
|
||||
// The actual text of the comment
|
||||
def text : String
|
||||
|
||||
def datePosted : Date
|
||||
|
||||
def toJson : JObject = {
|
||||
val userInJson = postedBy match {
|
||||
case Full(user) => user.toJson
|
||||
case _ => ("id" -> "") ~
|
||||
("provider" -> "") ~
|
||||
("display_name" -> "")
|
||||
}
|
||||
|
||||
("id" -> id_) ~
|
||||
("date" -> datePosted.toString) ~
|
||||
("comment" -> text) ~
|
||||
("view" -> viewId) ~
|
||||
("user" -> userInJson) ~
|
||||
("reply_to" -> "")
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.traits
|
||||
import java.util.Date
|
||||
|
||||
trait TransactionMetadata {
|
||||
|
||||
// Owner provided comment, done in OBP
|
||||
def ownerComment : Option[String]
|
||||
def ownerComment(comment : String) : Unit
|
||||
def comments : List[Comment]
|
||||
def addComment(userId : Long, viewId : Long, text : String, postedDate : Date) : Unit
|
||||
}
|
||||
trait OtherBankAccountMetadata
|
||||
{
|
||||
def publicAlias : String
|
||||
def privateAlias : String
|
||||
def moreInfo : String
|
||||
def url : String
|
||||
def imageUrl : String
|
||||
def openCorporatesUrl : String
|
||||
}
|
||||
@ -1,233 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.traits
|
||||
import java.util.Date
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
import net.liftweb.json.JsonAST.JString
|
||||
import net.liftweb.json.JsonAST.JField
|
||||
import net.liftweb.json._
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.http.JsonResponse
|
||||
import net.liftweb.http.LiftResponse
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
class ModeratedOtherBankAccount (filteredId : String, filteredLabel : AccountName,
|
||||
filteredNationalIdentifier : Option[String], filteredSWIFT_BIC : Option[Option[String]],
|
||||
filteredIBAN : Option[Option[String]], filteredBankName: Option[String],
|
||||
filteredNumber: Option[String], filteredMetadata : Option[ModeratedOtherBankAccountMetadata])
|
||||
{
|
||||
def id = filteredId
|
||||
def label = filteredLabel
|
||||
def nationalIdentifier = filteredNationalIdentifier
|
||||
def swift_bic = filteredSWIFT_BIC
|
||||
def iban = filteredIBAN
|
||||
def bankName = filteredBankName
|
||||
def number = filteredNumber
|
||||
def metadata = filteredMetadata
|
||||
def isAlias = filteredLabel.aliasType match{
|
||||
case Public | Private => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
object ModeratedOtherBankAccount {
|
||||
implicit def moderatedOtherBankAccount2Json(mOtherBank: ModeratedOtherBankAccount) : JObject = {
|
||||
val holderName = mOtherBank.label.display
|
||||
val isAlias = if(mOtherBank.isAlias) "yes" else "no"
|
||||
val number = mOtherBank.number getOrElse ""
|
||||
val kind = ""
|
||||
val bankIBAN = (for { //TODO: This should be handled a bit better... might want to revisit the Option stuff in ModeratedOtherAccount etc.
|
||||
i <- mOtherBank.iban
|
||||
iString <- i
|
||||
} yield iString).getOrElse("")
|
||||
val bankNatIdent = mOtherBank.nationalIdentifier getOrElse ""
|
||||
val bankName = mOtherBank.bankName getOrElse ""
|
||||
ModeratedBankAccount.bankJson(holderName, isAlias, number, kind, bankIBAN, bankNatIdent, bankName)
|
||||
}
|
||||
}
|
||||
|
||||
class ModeratedOtherBankAccountMetadata(filteredMoreInfo : Option[String],
|
||||
filteredUrl : Option[String], filteredImageUrl : Option[String], filteredOpenCorporatesUrl : Option[String]) {
|
||||
def moreInfo = filteredMoreInfo
|
||||
def url = filteredUrl
|
||||
def imageUrl = filteredImageUrl
|
||||
def openCorporatesUrl = filteredOpenCorporatesUrl
|
||||
}
|
||||
|
||||
object ModeratedOtherBankAccountMetadata {
|
||||
implicit def moderatedOtherBankAccountMetadata2Json(mOtherBankMeta: ModeratedOtherBankAccountMetadata) : JObject = {
|
||||
JObject(JField("blah", JString("test")) :: Nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ModeratedTransaction(filteredId: String, filteredBankAccount: Option[ModeratedBankAccount],
|
||||
filteredOtherBankAccount: Option[ModeratedOtherBankAccount], filteredMetaData : Option[ModeratedTransactionMetadata],
|
||||
filteredTransactionType: Option[String], filteredAmount: Option[BigDecimal], filteredCurrency: Option[String],
|
||||
filteredLabel: Option[Option[String]],filteredStartDate: Option[Date], filteredFinishDate: Option[Date],
|
||||
filteredBalance : String) {
|
||||
|
||||
//the filteredBlance type in this class is a string rather than Big decimal like in Transaction trait for snippet (display) reasons.
|
||||
//the view should be able to return a sign (- or +) or the real value. casting signs into bigdecimal is not possible
|
||||
def id = filteredId
|
||||
def bankAccount = filteredBankAccount
|
||||
def otherBankAccount = filteredOtherBankAccount
|
||||
def metadata = filteredMetaData
|
||||
def transactionType = filteredTransactionType
|
||||
def amount = filteredAmount
|
||||
def currency = filteredCurrency
|
||||
def label = filteredLabel
|
||||
def startDate = filteredStartDate
|
||||
def finishDate = filteredFinishDate
|
||||
def balance = filteredBalance
|
||||
|
||||
def dateOption2JString(date: Option[Date]) : JString = {
|
||||
JString(date.map(d => ModeratedTransaction.dateFormat.format(d)) getOrElse "")
|
||||
}
|
||||
|
||||
def toJson(view: View): JObject = {
|
||||
("view" -> view.permalink) ~
|
||||
("uuid" -> id) ~
|
||||
("this_account" -> bankAccount) ~
|
||||
("other_account" -> otherBankAccount) ~
|
||||
("details" ->
|
||||
("type_en" -> transactionType) ~ //TODO: Need translations for transaction types and a way to
|
||||
("type_de" -> transactionType) ~ // figure out what language the original type is in
|
||||
("posted" -> dateOption2JString(startDate)) ~
|
||||
("completed" -> dateOption2JString(finishDate)) ~
|
||||
("new_balance" ->
|
||||
("currency" -> currency.getOrElse("")) ~ //TODO: Need separate currency for balances and values?
|
||||
("amount" -> balance)) ~
|
||||
("value" ->
|
||||
("currency" -> currency.getOrElse("")) ~
|
||||
("amount" -> amount)))
|
||||
}
|
||||
}
|
||||
|
||||
object ModeratedTransaction {
|
||||
val dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
|
||||
}
|
||||
|
||||
class ModeratedTransactionMetadata(filteredOwnerComment : Option[String], filteredComments : Option[List[Comment]],
|
||||
addOwnerComment : Option[(String => Unit)], addCommentFunc: Option[(Long, Long, String, Date) => Unit])
|
||||
{
|
||||
def ownerComment = filteredOwnerComment
|
||||
def comments = filteredComments
|
||||
def ownerComment(text : String) = addOwnerComment match {
|
||||
case None => None
|
||||
case Some(o) => o.apply(text)
|
||||
}
|
||||
def addComment= addCommentFunc
|
||||
|
||||
}
|
||||
|
||||
object ModeratedTransactionMetadata {
|
||||
implicit def moderatedTransactionMetadata2Json(mTransactionMeta: ModeratedTransactionMetadata) : JObject = {
|
||||
JObject(JField("blah", JString("test")) :: Nil)
|
||||
}
|
||||
}
|
||||
|
||||
class ModeratedBankAccount(filteredId : String,
|
||||
filteredOwners : Option[Set[AccountOwner]], filteredAccountType : Option[String],
|
||||
filteredBalance: String, filteredCurrency : Option[String],
|
||||
filteredLabel : Option[String], filteredNationalIdentifier : Option[String],
|
||||
filteredSwift_bic : Option[Option[String]], filteredIban : Option[Option[String]],
|
||||
filteredNumber: Option[String], filteredBankName: Option[String])
|
||||
{
|
||||
def id = filteredId
|
||||
def owners = filteredOwners
|
||||
def accountType = filteredAccountType
|
||||
def balance = filteredBalance
|
||||
def currency = filteredCurrency
|
||||
def label = filteredLabel
|
||||
def nationalIdentifier = filteredNationalIdentifier
|
||||
def swift_bic = filteredSwift_bic
|
||||
def iban = filteredIban
|
||||
def number = filteredNumber
|
||||
def bankName = filteredBankName
|
||||
|
||||
def toJson = {
|
||||
//TODO: Decide if unauthorised info (I guess that is represented by a 'none' option'? I can't really remember)
|
||||
// should just disappear from the json or if an empty string should be used.
|
||||
//I think we decided to use empty strings. What was the point of all the options again?
|
||||
("number" -> number.getOrElse("")) ~
|
||||
("owners" -> owners.flatten.map(owner =>
|
||||
("id" ->owner.id) ~
|
||||
("name" -> owner.name))) ~
|
||||
("type" -> accountType.getOrElse("")) ~
|
||||
("balance" ->
|
||||
("currency" -> currency.getOrElse("")) ~
|
||||
("amount" -> balance)) ~
|
||||
("IBAN" -> iban.getOrElse(Some(""))) ~
|
||||
("date_opened" -> "")
|
||||
}
|
||||
}
|
||||
|
||||
object ModeratedBankAccount {
|
||||
|
||||
def bankJson(holderName: String, isAlias : String, number: String,
|
||||
kind: String, bankIBAN: String, bankNatIdent: String,
|
||||
bankName: String) : JObject = {
|
||||
("holder" ->
|
||||
(
|
||||
("name" -> holderName) ~
|
||||
("alias"-> isAlias)
|
||||
))~
|
||||
("number" -> number) ~
|
||||
("kind" -> kind) ~
|
||||
("bank" ->
|
||||
("IBAN" -> bankIBAN) ~
|
||||
("national_identifier" -> bankNatIdent) ~
|
||||
("name" -> bankName))
|
||||
}
|
||||
|
||||
implicit def moderatedBankAccount2Json(mBankAccount: ModeratedBankAccount) : JObject = {
|
||||
val holderName = mBankAccount.owners match{
|
||||
case Some(ownersSet) => if(ownersSet.size!=0)
|
||||
ownersSet.toList(0).name
|
||||
else
|
||||
""
|
||||
case _ => ""
|
||||
}
|
||||
val isAlias = "no"
|
||||
val number = mBankAccount.number getOrElse ""
|
||||
val kind = mBankAccount.accountType getOrElse ""
|
||||
val bankIBAN = (for { //TODO: This should be handled a bit better... might want to revisit the Option stuff in ModeratedOtherAccount etc.
|
||||
i <- mBankAccount.iban
|
||||
iString <- i
|
||||
} yield iString).getOrElse("")
|
||||
val bankNatIdent = mBankAccount.nationalIdentifier getOrElse ""
|
||||
val bankName = mBankAccount.bankName getOrElse ""
|
||||
bankJson(holderName, isAlias, number, kind, bankIBAN, bankNatIdent, bankName)
|
||||
}
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.model.traits
|
||||
import scala.math.BigDecimal
|
||||
import java.util.Date
|
||||
|
||||
trait Transaction {
|
||||
|
||||
def id : String
|
||||
|
||||
var thisAccount : BankAccount
|
||||
|
||||
def otherAccount : OtherBankAccount
|
||||
|
||||
def metadata : TransactionMetadata
|
||||
|
||||
//E.g. cash withdrawal, electronic payment, etc.
|
||||
def transactionType : String
|
||||
|
||||
//TODO: Check if BigDecimal is an appropriate data type
|
||||
def amount : BigDecimal
|
||||
|
||||
//ISO 4217, e.g. EUR, GBP, USD, etc.
|
||||
def currency : String
|
||||
|
||||
// Bank provided comment
|
||||
def label : Option[String]
|
||||
|
||||
// The date the transaction was initiated
|
||||
def startDate : Date
|
||||
|
||||
// The date when the money finished changing hands
|
||||
def finishDate : Date
|
||||
|
||||
//the new balance for the bank account
|
||||
//TODO : Rethink this
|
||||
def balance : BigDecimal
|
||||
|
||||
}
|
||||
@ -1,421 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
package code.model.traits
|
||||
import code.snippet.CustomEditable
|
||||
import net.liftweb.http.SHtml
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.JsonAST.JObject
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.common.Empty
|
||||
import net.liftweb.common.Full
|
||||
|
||||
class AliasType
|
||||
class Alias extends AliasType
|
||||
object Public extends Alias
|
||||
object Private extends Alias
|
||||
object NoAlias extends AliasType
|
||||
case class AccountName(display: String, aliasType: AliasType)
|
||||
|
||||
trait View {
|
||||
|
||||
//e.g. "Anonymous", "Authorities", "Our Network", etc.
|
||||
def id: Long
|
||||
def name: String
|
||||
def description : String
|
||||
def permalink : String
|
||||
|
||||
//the view settings
|
||||
def usePrivateAliasIfOneExists: Boolean
|
||||
def usePublicAliasIfOneExists: Boolean
|
||||
|
||||
//reading access
|
||||
|
||||
//transaction fields
|
||||
def canSeeTransactionThisBankAccount : Boolean
|
||||
def canSeeTransactionOtherBankAccount : Boolean
|
||||
def canSeeTransactionMetadata : Boolean
|
||||
def canSeeTransactionLabel: Boolean
|
||||
def canSeeTransactionAmount: Boolean
|
||||
def canSeeTransactionType: Boolean
|
||||
def canSeeTransactionCurrency: Boolean
|
||||
def canSeeTransactionStartDate: Boolean
|
||||
def canSeeTransactionFinishDate: Boolean
|
||||
def canSeeTransactionBalance: Boolean
|
||||
|
||||
//transaction metadata
|
||||
def canSeeComments: Boolean
|
||||
def canSeeOwnerComment: Boolean
|
||||
|
||||
//Bank account fields
|
||||
def canSeeBankAccountOwners : Boolean
|
||||
def canSeeBankAccountType : Boolean
|
||||
def canSeeBankAccountBalance : Boolean
|
||||
def canSeeBankAccountBalancePositiveOrNegative : Boolean
|
||||
def canSeeBankAccountCurrency : Boolean
|
||||
def canSeeBankAccountLabel : Boolean
|
||||
def canSeeBankAccountNationalIdentifier : Boolean
|
||||
def canSeeBankAccountSwift_bic : Boolean
|
||||
def canSeeBankAccountIban : Boolean
|
||||
def canSeeBankAccountNumber : Boolean
|
||||
def canSeeBankAccountName : Boolean
|
||||
|
||||
//other bank account fields
|
||||
def canSeeOtherAccountNationalIdentifier : Boolean
|
||||
def canSeeSWIFT_BIC : Boolean
|
||||
def canSeeOtherAccountIBAN : Boolean
|
||||
def canSeeOtherAccountBankName : Boolean
|
||||
def canSeeOtherAccountNumber : Boolean
|
||||
def canSeeOtherAccountMetadata :Boolean
|
||||
|
||||
//other bank account meta data
|
||||
def canSeeMoreInfo: Boolean
|
||||
def canSeeUrl: Boolean
|
||||
def canSeeImageUrl: Boolean
|
||||
def canSeeOpenCorporatesUrl: Boolean
|
||||
|
||||
//writing access
|
||||
def canEditOwnerComment: Boolean
|
||||
def canAddComments : Boolean
|
||||
|
||||
// In the future we can add a method here to allow someone to show only transactions over a certain limit
|
||||
|
||||
def moderate(transaction: Transaction): ModeratedTransaction = {
|
||||
//transaction data
|
||||
val transactionId = transaction.id
|
||||
|
||||
val thisBankAccount =
|
||||
if(canSeeTransactionThisBankAccount)
|
||||
{
|
||||
val owners = if(canSeeBankAccountOwners) Some(transaction.thisAccount.owners) else None
|
||||
val accountType = if(canSeeBankAccountType) Some(transaction.thisAccount.accountType) else None
|
||||
val balance = if(canSeeBankAccountBalance) {
|
||||
transaction.thisAccount.balance.toString
|
||||
} else if (canSeeBankAccountBalancePositiveOrNegative) {
|
||||
if(transaction.thisAccount.balance.toString.startsWith("-")) "-" else "+"
|
||||
} else ""
|
||||
val currency = if(canSeeBankAccountCurrency) Some(transaction.thisAccount.currency) else None
|
||||
val label = if(canSeeBankAccountLabel) Some(transaction.thisAccount.label) else None
|
||||
val number = if(canSeeBankAccountNumber) Some(transaction.thisAccount.number) else None
|
||||
val bankName = if(canSeeBankAccountName) Some(transaction.thisAccount.bankName) else None
|
||||
val nationalIdentifier =
|
||||
if(canSeeBankAccountNationalIdentifier)
|
||||
Some(transaction.thisAccount.nationalIdentifier)
|
||||
else
|
||||
None
|
||||
val swift_bic =
|
||||
if(canSeeBankAccountSwift_bic)
|
||||
Some(transaction.thisAccount.swift_bic)
|
||||
else
|
||||
None
|
||||
val iban =
|
||||
if(canSeeBankAccountIban)
|
||||
Some(transaction.thisAccount.iban)
|
||||
else
|
||||
None
|
||||
Some(new ModeratedBankAccount(transaction.thisAccount.id, owners, accountType, balance, currency, label,
|
||||
nationalIdentifier, swift_bic, iban, number, bankName))
|
||||
}
|
||||
else
|
||||
None
|
||||
|
||||
val otherBankAccount =
|
||||
if (canSeeTransactionOtherBankAccount)
|
||||
{
|
||||
//other account data
|
||||
var otherAccountId = transaction.otherAccount.id
|
||||
val otherAccountLabel: AccountName =
|
||||
{
|
||||
val realName = transaction.otherAccount.label
|
||||
if (usePublicAliasIfOneExists) {
|
||||
|
||||
val publicAlias = transaction.otherAccount.metadata.publicAlias
|
||||
|
||||
if (! publicAlias.isEmpty ) AccountName(publicAlias, Public)
|
||||
else AccountName(realName, NoAlias)
|
||||
|
||||
} else if (usePrivateAliasIfOneExists) {
|
||||
|
||||
val privateAlias = transaction.otherAccount.metadata.privateAlias
|
||||
|
||||
if (! privateAlias.isEmpty) AccountName(privateAlias, Private)
|
||||
else AccountName(realName, Private)
|
||||
} else
|
||||
AccountName(realName, NoAlias)
|
||||
}
|
||||
val otherAccountNationalIdentifier = if (canSeeOtherAccountNationalIdentifier) Some(transaction.otherAccount.nationalIdentifier) else None
|
||||
val otherAccountSWIFT_BIC = if (canSeeSWIFT_BIC) Some(transaction.otherAccount.swift_bic) else None
|
||||
val otherAccountIBAN = if(canSeeOtherAccountIBAN) Some(transaction.otherAccount.iban) else None
|
||||
val otherAccountBankName = if(canSeeOtherAccountBankName) Some(transaction.otherAccount.bankName) else None
|
||||
val otherAccountNumber = if(canSeeOtherAccountNumber) Some(transaction.otherAccount.number) else None
|
||||
val otherAccountMetadata =
|
||||
if(canSeeOtherAccountMetadata)
|
||||
{
|
||||
//other bank account metadata
|
||||
val moreInfo =
|
||||
if (canSeeMoreInfo) Some(transaction.otherAccount.metadata.moreInfo)
|
||||
else None
|
||||
val url =
|
||||
if (canSeeUrl) Some(transaction.otherAccount.metadata.url)
|
||||
else None
|
||||
val imageUrl =
|
||||
if (canSeeImageUrl) Some(transaction.otherAccount.metadata.imageUrl)
|
||||
else None
|
||||
val openCorporatesUrl =
|
||||
if (canSeeOpenCorporatesUrl) Some(transaction.otherAccount.metadata.openCorporatesUrl)
|
||||
else None
|
||||
|
||||
Some(new ModeratedOtherBankAccountMetadata(moreInfo, url, imageUrl, openCorporatesUrl))
|
||||
}
|
||||
else
|
||||
None
|
||||
|
||||
Some(new ModeratedOtherBankAccount(otherAccountId,otherAccountLabel, otherAccountNationalIdentifier,
|
||||
otherAccountSWIFT_BIC, otherAccountIBAN, otherAccountBankName, otherAccountNumber, otherAccountMetadata))
|
||||
}
|
||||
else
|
||||
None
|
||||
|
||||
//transation metadata
|
||||
val transactionMetadata =
|
||||
if(canSeeTransactionMetadata)
|
||||
{
|
||||
val ownerComment = if (canSeeOwnerComment) transaction.metadata.ownerComment else None
|
||||
val comments =
|
||||
if (canSeeComments)
|
||||
Some(transaction.metadata.comments.filter(comment => comment.viewId==id))
|
||||
else None
|
||||
val addCommentFunc= if(canAddComments) Some(transaction.metadata.addComment _) else None
|
||||
val addOwnerCommentFunc:Option[String=> Unit] = if (canEditOwnerComment) Some(transaction.metadata.ownerComment _) else None
|
||||
new Some(new ModeratedTransactionMetadata(ownerComment,comments,addOwnerCommentFunc,addCommentFunc))
|
||||
}
|
||||
else
|
||||
None
|
||||
|
||||
val transactionType =
|
||||
if (canSeeTransactionType) Some(transaction.transactionType)
|
||||
else None
|
||||
|
||||
val transactionAmount =
|
||||
if (canSeeTransactionAmount) Some(transaction.amount)
|
||||
else None
|
||||
|
||||
val transactionCurrency =
|
||||
if (canSeeTransactionCurrency) Some(transaction.currency)
|
||||
else None
|
||||
|
||||
val transactionLabel =
|
||||
if (canSeeTransactionLabel) Some(transaction.label)
|
||||
else None
|
||||
|
||||
val transactionStartDate =
|
||||
if (canSeeTransactionStartDate) Some(transaction.startDate)
|
||||
else None
|
||||
|
||||
val transactionFinishDate =
|
||||
if (canSeeTransactionFinishDate) Some(transaction.finishDate)
|
||||
else None
|
||||
|
||||
val transactionBalance =
|
||||
if (canSeeTransactionBalance) transaction.balance.toString()
|
||||
else ""
|
||||
|
||||
new ModeratedTransaction(transactionId, thisBankAccount, otherBankAccount, transactionMetadata,
|
||||
transactionType, transactionAmount, transactionCurrency, transactionLabel, transactionStartDate,
|
||||
transactionFinishDate, transactionBalance)
|
||||
}
|
||||
|
||||
def moderate(bankAccount: BankAccount) : Box[ModeratedBankAccount] = {
|
||||
if(bankAccount.allowAnnoymousAccess) {
|
||||
val owners : Set[AccountOwner] = if(canSeeBankAccountOwners) bankAccount.owners else Set()
|
||||
val balance = if(canSeeBankAccountBalance){
|
||||
bankAccount.balance.toString
|
||||
} else if(canSeeBankAccountBalancePositiveOrNegative) {
|
||||
if(bankAccount.balance.toString.startsWith("-")) "-" else "+"
|
||||
} else ""
|
||||
val accountType = if(canSeeBankAccountType) Some(bankAccount.accountType) else None
|
||||
val currency = if(canSeeBankAccountCurrency) Some(bankAccount.currency) else None
|
||||
val label = if(canSeeBankAccountLabel) Some(bankAccount.label) else None
|
||||
val nationalIdentifier = if(canSeeBankAccountNationalIdentifier) Some(bankAccount.label) else None
|
||||
val swiftBic = if(canSeeBankAccountSwift_bic) Some(bankAccount.swift_bic) else None
|
||||
val iban = if(canSeeBankAccountIban) Some(bankAccount.iban) else None
|
||||
val number = if(canSeeBankAccountNumber) Some(bankAccount.number) else None
|
||||
val bankName = if(canSeeBankAccountName) Some(bankAccount.bankName) else None
|
||||
|
||||
Full(new ModeratedBankAccount(filteredId = bankAccount.id,
|
||||
filteredOwners = Some(owners),
|
||||
filteredAccountType = accountType,
|
||||
filteredBalance = balance,
|
||||
filteredCurrency = currency,
|
||||
filteredLabel = label,
|
||||
filteredNationalIdentifier = nationalIdentifier,
|
||||
filteredSwift_bic = swiftBic,
|
||||
filteredIban = iban,
|
||||
filteredNumber = number,
|
||||
filteredBankName = bankName
|
||||
))
|
||||
}
|
||||
else Empty
|
||||
}
|
||||
|
||||
def toJson : JObject = {
|
||||
("name" -> name) ~
|
||||
("description" -> description)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//An implementation that has the least amount of permissions possible
|
||||
class BaseView extends View {
|
||||
def id = 1
|
||||
def name = "Restricted"
|
||||
def permalink = "restricted"
|
||||
def description = ""
|
||||
|
||||
//the view settings
|
||||
def usePrivateAliasIfOneExists = true
|
||||
def usePublicAliasIfOneExists = true
|
||||
|
||||
//reading access
|
||||
|
||||
//transaction fields
|
||||
def canSeeTransactionThisBankAccount = false
|
||||
def canSeeTransactionOtherBankAccount = false
|
||||
def canSeeTransactionMetadata = false
|
||||
def canSeeTransactionLabel = false
|
||||
def canSeeTransactionAmount = false
|
||||
def canSeeTransactionType = false
|
||||
def canSeeTransactionCurrency = false
|
||||
def canSeeTransactionStartDate = false
|
||||
def canSeeTransactionFinishDate = false
|
||||
def canSeeTransactionBalance = false
|
||||
|
||||
//transaction metadata
|
||||
def canSeeComments = false
|
||||
def canSeeOwnerComment = false
|
||||
|
||||
//Bank account fields
|
||||
def canSeeBankAccountOwners = false
|
||||
def canSeeBankAccountType = false
|
||||
def canSeeBankAccountBalance = false
|
||||
def canSeeBankAccountBalancePositiveOrNegative = false
|
||||
def canSeeBankAccountCurrency = false
|
||||
def canSeeBankAccountLabel = false
|
||||
def canSeeBankAccountNationalIdentifier = false
|
||||
def canSeeBankAccountSwift_bic = false
|
||||
def canSeeBankAccountIban = false
|
||||
def canSeeBankAccountNumber = false
|
||||
def canSeeBankAccountName = false
|
||||
|
||||
//other bank account fields
|
||||
def canSeeOtherAccountNationalIdentifier = false
|
||||
def canSeeSWIFT_BIC = false
|
||||
def canSeeOtherAccountIBAN = false
|
||||
def canSeeOtherAccountBankName = false
|
||||
def canSeeOtherAccountNumber = false
|
||||
def canSeeOtherAccountMetadata = false
|
||||
|
||||
//other bank account meta data
|
||||
def canSeeMoreInfo = false
|
||||
def canSeeUrl = false
|
||||
def canSeeImageUrl = false
|
||||
def canSeeOpenCorporatesUrl = false
|
||||
|
||||
//writing access
|
||||
def canEditOwnerComment = false
|
||||
def canAddComments = false
|
||||
|
||||
}
|
||||
|
||||
class FullView extends View {
|
||||
def id = 2
|
||||
def name = "Full"
|
||||
def permalink ="full"
|
||||
def description = ""
|
||||
|
||||
//the view settings
|
||||
def usePrivateAliasIfOneExists = false
|
||||
def usePublicAliasIfOneExists = false
|
||||
|
||||
//reading access
|
||||
|
||||
//transaction fields
|
||||
def canSeeTransactionThisBankAccount = true
|
||||
def canSeeTransactionOtherBankAccount = true
|
||||
def canSeeTransactionMetadata = true
|
||||
def canSeeTransactionLabel = true
|
||||
def canSeeTransactionAmount = true
|
||||
def canSeeTransactionType = true
|
||||
def canSeeTransactionCurrency = true
|
||||
def canSeeTransactionStartDate = true
|
||||
def canSeeTransactionFinishDate = true
|
||||
def canSeeTransactionBalance = true
|
||||
|
||||
//transaction metadata
|
||||
def canSeeComments = true
|
||||
def canSeeOwnerComment = true
|
||||
|
||||
//Bank account fields
|
||||
def canSeeBankAccountOwners = true
|
||||
def canSeeBankAccountType = true
|
||||
def canSeeBankAccountBalance = true
|
||||
def canSeeBankAccountBalancePositiveOrNegative = true
|
||||
def canSeeBankAccountCurrency = true
|
||||
def canSeeBankAccountLabel = true
|
||||
def canSeeBankAccountNationalIdentifier = true
|
||||
def canSeeBankAccountSwift_bic = true
|
||||
def canSeeBankAccountIban = true
|
||||
def canSeeBankAccountNumber = true
|
||||
def canSeeBankAccountName = true
|
||||
|
||||
//other bank account fields
|
||||
def canSeeOtherAccountNationalIdentifier = true
|
||||
def canSeeSWIFT_BIC = true
|
||||
def canSeeOtherAccountIBAN = true
|
||||
def canSeeOtherAccountMetadata = true
|
||||
def canSeeOtherAccountBankName = true
|
||||
def canSeeOtherAccountNumber = true
|
||||
|
||||
//other bank account meta data
|
||||
def canSeeMoreInfo = true
|
||||
def canSeeUrl = true
|
||||
def canSeeImageUrl = true
|
||||
def canSeeOpenCorporatesUrl = true
|
||||
|
||||
//writing access
|
||||
def canEditOwnerComment = true
|
||||
def canAddComments = true
|
||||
|
||||
}
|
||||
|
||||
|
||||
189
MavLift/src/main/scala/code/snippet/AccountRegistration.scala
Normal file
189
MavLift/src/main/scala/code/snippet/AccountRegistration.scala
Normal file
@ -0,0 +1,189 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.snippet
|
||||
|
||||
import code.model.dataAccess.{OBPUser,HostedBank}
|
||||
import net.liftweb.common.{Full,Box,Empty,Failure}
|
||||
import scala.xml.NodeSeq
|
||||
import net.liftweb.util.CssSel
|
||||
import net.liftweb.util.Helpers._
|
||||
import net.liftweb.util.Props
|
||||
import net.liftweb.http.{S,SHtml,RequestVar}
|
||||
import code.pgp.PgpEncryption
|
||||
import net.liftweb.http.js.JsCmd
|
||||
import net.liftweb.http.js.JsCmds.Noop
|
||||
import scala.xml.Text
|
||||
import net.liftweb.util.Mailer
|
||||
import Mailer._
|
||||
import net.liftweb.common.Loggable
|
||||
|
||||
class AccountRegistration extends Loggable {
|
||||
|
||||
private object bankName extends RequestVar("")
|
||||
private object accountNumber extends RequestVar("")
|
||||
private object accountPIN extends RequestVar("")
|
||||
private object publicAccess extends RequestVar(false)
|
||||
private object accountHolder extends RequestVar("")
|
||||
private object accountKind extends RequestVar("")
|
||||
private object accountLabel extends RequestVar("")
|
||||
private object accountName extends RequestVar("")
|
||||
|
||||
def renderForm = {
|
||||
OBPUser.currentUser match {
|
||||
case Full(user) => {
|
||||
//load the suported banks list from the database
|
||||
val banks = "Choose a Bank" :: HostedBank.findAll.map(_.name.get)
|
||||
val options = Map("yes" -> true,"no" -> false)
|
||||
val optionsSwaped = options.map{_.swap}
|
||||
|
||||
//get a boolean value from a 'yes' or 'no' string
|
||||
def getBooleanValue(text : Box[String]) =
|
||||
text match {
|
||||
case Full(value) => tryo{
|
||||
options(value)
|
||||
} match {
|
||||
case Full(boolean) => boolean
|
||||
case _ => false
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def check() =
|
||||
//check that all the parameters are here
|
||||
if( !accountNumber.is.isEmpty && !accountPIN.is.isEmpty &
|
||||
!accountName.is.isEmpty && !accountHolder.is.isEmpty &
|
||||
!accountKind.is.isEmpty && ! accountLabel.is.isEmpty &
|
||||
bankName.is != "Choose a Bank" )
|
||||
{
|
||||
var reponceText = "Submission Failed. Please try later."
|
||||
var reponceId = "submissionFailed"
|
||||
val fileName = bankName.is+"-"+accountNumber.is+"-"+user.emailAddress
|
||||
for{
|
||||
//load the public key and output directory path
|
||||
publicKey <- Props.get("publicKeyPath")
|
||||
outputFilesDirectory <- Props.get("outputFilesDirectory")
|
||||
}yield tryo{
|
||||
//store the Pin code into an encrypted file
|
||||
PgpEncryption.encryptToFile(
|
||||
accountPIN.is,
|
||||
publicKey,
|
||||
outputFilesDirectory+"/"+fileName+".pin")
|
||||
} match {
|
||||
case Full(encryptedPin) => {
|
||||
//send an email to the administration so we can setup the account
|
||||
//prepare the data to be sent into the email body
|
||||
val emailBody =
|
||||
"The following account needs to activated : " +"\n"+
|
||||
"bank name : " + bankName.is +"\n"+
|
||||
"account number : " + accountNumber.is +"\n"+
|
||||
"account name : " + accountName.is +"\n"+
|
||||
"account holder : " + accountHolder.is +"\n"+
|
||||
"account label : " + accountLabel.is +"\n"+
|
||||
"account kind : " + accountKind.is +"\n"+
|
||||
"public view : " + publicAccess.is.toString +"\n"+
|
||||
"user email : " + user.emailAddress +"\n"+
|
||||
"The PIN code is in this file : "+ outputFilesDirectory+"/"+fileName+".pin"+"\n"
|
||||
val accountNotificationemails = Props.get("accountNotificationemails") match {
|
||||
case Full(emails) => emails.split(",",0)
|
||||
case _ => Array()
|
||||
}
|
||||
|
||||
tryo {
|
||||
accountNotificationemails.foreach ( email =>
|
||||
Mailer.sendMail(From("noreply@openbankproject.com"),Subject("[SoFi]Bank account Activation"),
|
||||
To(email),PlainMailBodyType(emailBody))
|
||||
)
|
||||
} match {
|
||||
case Failure(message, exception, chain) =>
|
||||
logger.error("problem while sending email: " + message)
|
||||
case _ =>
|
||||
logger.info("successfully sent email")
|
||||
}
|
||||
reponceText = "Submission succeded. You will receive an email notification once the bank account will be setup by the administrator."
|
||||
reponceId = "submissionSuccess"
|
||||
}
|
||||
case _ => //nothing to do the text and Id are allready set
|
||||
}
|
||||
//set the fields to their default values
|
||||
bankName.set("Choose a Bank")
|
||||
accountNumber.set("")
|
||||
accountPIN.set("")
|
||||
publicAccess.set(false)
|
||||
accountHolder.set("")
|
||||
accountKind.set("")
|
||||
accountLabel.set("")
|
||||
accountName.set("")
|
||||
//return a message
|
||||
S.notice("submissionMessage", SHtml.span(Text(reponceText), Noop,("id",reponceId)))
|
||||
}
|
||||
else
|
||||
{
|
||||
if(bankName.is == "Choose a Bank")
|
||||
S.error("bankError","Bank not selected ! ")
|
||||
if(accountNumber.is.isEmpty)
|
||||
S.error("accountNumberError","Account Number Empty ! ")
|
||||
if(accountPIN.is.isEmpty)
|
||||
S.error("accountPINError","Account PIN Empty ! ")
|
||||
if(accountHolder.is.isEmpty)
|
||||
S.error("accountHolderError","Account Holder Empty ! ")
|
||||
if(accountKind.is.isEmpty)
|
||||
S.error("accountKindError","Account Kind Empty ! ")
|
||||
if(accountLabel.is.isEmpty)
|
||||
S.error("accountLabelError","Account label Empty ! ")
|
||||
if(accountName.is.isEmpty)
|
||||
S.error("accountNameError","Account Name Empty ! ")
|
||||
}
|
||||
|
||||
//now we create the form fields
|
||||
"#bankListCol" #> SHtml.selectElem(banks,Full(bankName.is),("id","bankList"))((v : String) => bankName.set(v)) &
|
||||
"#accountNumberCol" #> SHtml.textElem(accountNumber,("id","accountNumber"),("placeholder","123456")) &
|
||||
"#accountPINCol" #> SHtml.passwordElem(accountPIN,("id","accountPIN"),("placeholder","*******")) &
|
||||
"#publicViewCol" #> SHtml.radioElem(options.keys.toList,Full(optionsSwaped(publicAccess.is)))((v : Box[String]) => publicAccess.set(getBooleanValue(v))).toForm &
|
||||
"#accountHolderCol" #> SHtml.textElem(accountHolder,("id","accountHolder"),("placeholder","John Doe")) &
|
||||
"#accountKindCol" #> SHtml.textElem(accountKind,("id","accountKind"),("placeholder","saving, current, ...")) &
|
||||
"#accountLabelCol" #> SHtml.textElem(accountLabel,("id","accountLabel"),("placeholder","John main buisness account,...")) &
|
||||
"#accountNameCol" #> SHtml.textElem(accountName,("id","accountName"),("placeholder","mycompany, personal, etc")) &
|
||||
"type=submit" #> SHtml.onSubmitUnit(check) &
|
||||
"#loginMsg" #> NodeSeq.Empty
|
||||
}
|
||||
case _ =>
|
||||
//if the user is not logged in, we hide the form and ask him to login
|
||||
"#submitAccount" #> NodeSeq.Empty &
|
||||
"#loginMsg * " #> {
|
||||
Text("You must ") ++
|
||||
SHtml.link(OBPUser.loginPageURL,() => {},Text("login"),("title","signup/login")) ++
|
||||
Text(" before you can connect your bank account! ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
MavLift/src/main/scala/code/snippet/ConsumerRegistration.scala
Normal file
126
MavLift/src/main/scala/code/snippet/ConsumerRegistration.scala
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package code.snippet
|
||||
|
||||
import net.liftweb.util.Helpers._
|
||||
import code.model.Consumer
|
||||
import net.liftweb.http.S
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.http.SHtml
|
||||
import net.liftweb.http.RequestVar
|
||||
import net.liftweb.util.FieldError
|
||||
import net.liftweb.util.Helpers
|
||||
|
||||
class ConsumerRegistration {
|
||||
|
||||
val NOOP_SELECTOR = "#i_am_an_id_that_should_never_exist" #> ""
|
||||
|
||||
private object nameVar extends RequestVar("")
|
||||
private object appTypeVar extends RequestVar[Consumer.appType.enum.AppType](Consumer.appType.enum.values.head)
|
||||
private object descriptionVar extends RequestVar("")
|
||||
private object devEmailVar extends RequestVar("")
|
||||
|
||||
def registerForm = {
|
||||
|
||||
def registerWithoutWarnings =
|
||||
register &
|
||||
".registration-error" #> ""
|
||||
|
||||
def register = {
|
||||
".register" #> {
|
||||
".app-type-option" #> {
|
||||
val appTypes = Consumer.appType.enum.values.map(appType => appType.toString)
|
||||
appTypes.map(t => {
|
||||
val selected = appTypeVar.get.toString == t
|
||||
|
||||
def markIfSelected =
|
||||
if(selected) "* [selected]" #> "selected"
|
||||
else NOOP_SELECTOR
|
||||
|
||||
markIfSelected &
|
||||
"* *" #> t &
|
||||
"* [value]" #> t
|
||||
})
|
||||
} &
|
||||
"name=app-name [value]" #> nameVar.get &
|
||||
"name=app-description *" #> descriptionVar.get &
|
||||
"name=app-developer [value]" #> devEmailVar.get
|
||||
} &
|
||||
".success" #> ""
|
||||
}
|
||||
|
||||
def showResults(consumer : Consumer) = {
|
||||
//thanks for registering, here's your key, etc.
|
||||
".app-name *" #> consumer.name.get &
|
||||
".app-type *" #> consumer.appType.get.toString &
|
||||
".app-description *" #> consumer.description.get &
|
||||
".app-developer *" #> consumer.developerEmail.get &
|
||||
".auth-key *" #> consumer.key.get &
|
||||
".secret-key *" #> consumer.secret.get &
|
||||
".registration" #> ""
|
||||
}
|
||||
|
||||
def saveAndShowResults(consumer : Consumer) = {
|
||||
consumer.isActive(true).key(Helpers.randomString(40).toLowerCase).secret(Helpers.randomString(40).toLowerCase).save
|
||||
showResults(consumer)
|
||||
}
|
||||
|
||||
def showErrors(errors : List[FieldError]) = {
|
||||
register &
|
||||
".registration-error *" #> errors.map(_.msg.toString).mkString(", ")
|
||||
}
|
||||
|
||||
def analyseResult = {
|
||||
val name = S.param("app-name") getOrElse ""
|
||||
val appType = S.param("app-type").flatMap(typeString => Consumer.appType.enum.values.find(p => p.toString == typeString)) getOrElse
|
||||
Consumer.appType.enum.values.head
|
||||
val appDescription = S.param("app-description") getOrElse ""
|
||||
val developerEmail = S.param("app-developer") getOrElse ""
|
||||
|
||||
val consumer = Consumer.create.name(name).appType(appType).description(appDescription).developerEmail(developerEmail)
|
||||
|
||||
val errors = consumer.validate
|
||||
nameVar.set(name)
|
||||
appTypeVar.set(appType)
|
||||
descriptionVar.set(appDescription)
|
||||
devEmailVar.set(developerEmail)
|
||||
|
||||
if(errors.size == 0) saveAndShowResults(consumer)
|
||||
else showErrors(errors)
|
||||
}
|
||||
|
||||
if(S.post_?) analyseResult
|
||||
else register
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.snippet
|
||||
import net.liftweb.http.SHtml
|
||||
import scala.xml.NodeSeq
|
||||
import net.liftweb.http.js.JsCmd
|
||||
import scala.xml.Text
|
||||
|
||||
object CustomEditable {
|
||||
|
||||
//Borrows very heavily from SHtml.ajaxEditable
|
||||
//TODO: This should go. There is too much presentation stuff living here in the code
|
||||
def editable(label : => String, editForm: => NodeSeq, onSubmit: () => JsCmd, defaultValue: String): NodeSeq = {
|
||||
import net.liftweb.http.js
|
||||
import net.liftweb.http.S
|
||||
import js.{ jquery, JsCmd, JsCmds, JE }
|
||||
import jquery.JqJsCmds
|
||||
import JsCmds.{ Noop, SetHtml }
|
||||
import JE.Str
|
||||
import JqJsCmds.{ Hide, Show }
|
||||
import net.liftweb.util.Helpers
|
||||
|
||||
val divName = Helpers.nextFuncName
|
||||
val dispName = divName + "_display"
|
||||
val editName = divName + "_edit"
|
||||
|
||||
def swapJsCmd(show: String, hide: String): JsCmd = Show(show) & Hide(hide)
|
||||
|
||||
def setAndSwap(show: String, showContents: => NodeSeq, hide: String): JsCmd =
|
||||
(SHtml.ajaxCall(Str("ignore"), { ignore: String => SetHtml(show, showContents) })._2.cmd & swapJsCmd(show, hide))
|
||||
|
||||
val editClass = "edit"
|
||||
val addClass = "add"
|
||||
def aClass = if (label.equals("")) addClass else editClass
|
||||
def displayText = if (label.equals("")) defaultValue else label
|
||||
|
||||
def displayMarkup: NodeSeq = {
|
||||
label match {
|
||||
case "" => {
|
||||
<div onclick={ setAndSwap(editName, editMarkup, dispName).toJsCmd + " return false;" }><a href="#" class={ addClass }>{
|
||||
" " ++ displayText
|
||||
}</a></div>
|
||||
}
|
||||
case _ => {
|
||||
<div>
|
||||
<a href="#" class={ editClass } onclick={ setAndSwap(editName, editMarkup, dispName).toJsCmd + " return false;" }/>
|
||||
<span class="text">{ label }</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def editMarkup: NodeSeq = {
|
||||
val formData: NodeSeq =
|
||||
editForm ++ <br />
|
||||
<input class="submit" style="float:left;" type="image" src="/media/images/submit.png"/> ++
|
||||
SHtml.hidden(onSubmit, ("float", "left")) ++
|
||||
<input type="image" src="/media/images/cancel.png" onclick={ swapJsCmd(dispName, editName).toJsCmd + " return false;" }/>
|
||||
|
||||
SHtml.ajaxForm(formData,
|
||||
Noop,
|
||||
setAndSwap(dispName, displayMarkup, editName))
|
||||
}
|
||||
|
||||
<div>
|
||||
<div id={ dispName }>
|
||||
{ displayMarkup }
|
||||
</div>
|
||||
<div id={ editName } style="display: none;">
|
||||
{ editMarkup }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
}
|
||||
221
MavLift/src/main/scala/code/snippet/Nav.scala
Normal file
221
MavLift/src/main/scala/code/snippet/Nav.scala
Normal file
@ -0,0 +1,221 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
|
||||
package code.snippet
|
||||
import scala.xml.NodeSeq
|
||||
import net.liftweb.http.S
|
||||
import net.liftweb.http.LiftRules
|
||||
import net.liftweb.util.Helpers
|
||||
import net.liftweb.util.Helpers._
|
||||
import scala.xml.Group
|
||||
import net.liftweb.sitemap.Loc
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.common.Empty
|
||||
import net.liftweb.sitemap.SiteMapSingleton
|
||||
import code.model.dataAccess.{OBPUser,Account, LocalStorage}
|
||||
import net.liftweb.http.SHtml
|
||||
import net.liftweb.http.js.JsCmd
|
||||
import net.liftweb.http.js.JsCmds._Noop
|
||||
import code.model.BankAccount
|
||||
|
||||
class Nav {
|
||||
|
||||
def eraseMenu =
|
||||
"* * " #> ""
|
||||
def views :net.liftweb.util.CssSel = {
|
||||
val url = S.uri.split("/",0)
|
||||
if(url.size>4)
|
||||
OBPUser.currentUser match {
|
||||
case Full(user) => {
|
||||
val bankAccount = BankAccount(url(2), url(4))
|
||||
val viewsListBox = for {
|
||||
b <- bankAccount
|
||||
} yield user.permittedViews(b)
|
||||
val viewsList = viewsListBox getOrElse Nil
|
||||
if(viewsList.size>0)
|
||||
".navitem *" #> {
|
||||
viewsList.toList.map(view => {
|
||||
val viewUrl = "/banks/"+url(2)+"/accounts/"+url(4)+"/"+view.permalink
|
||||
".navlink [href]" #> {viewUrl} &
|
||||
".navlink *" #> view.name &
|
||||
".navlink [class+]" #> markIfSelected(viewUrl)
|
||||
})}
|
||||
else
|
||||
eraseMenu
|
||||
}
|
||||
case _ => LocalStorage.getAccount(url(2), url(4)) match {
|
||||
case Full(account) => if(account.anonAccess.is)
|
||||
".navitem *" #> {
|
||||
val anoymousUrl = "/banks/"+url(2)+"/accounts/"+url(4)+"/public"
|
||||
".navlink [href]" #> {anoymousUrl} &
|
||||
".navlink *" #> "Public" &
|
||||
".navlink [class+]" #> markIfSelected(anoymousUrl)
|
||||
}
|
||||
else
|
||||
eraseMenu
|
||||
case _ => eraseMenu
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
eraseMenu
|
||||
}
|
||||
|
||||
def management = {
|
||||
val url = S.uri.split("/", 0)
|
||||
|
||||
def getManagement = for {
|
||||
user <- OBPUser.currentUser
|
||||
bankAccount <- BankAccount(url(2), url(4))
|
||||
if (user.hasMangementAccess(bankAccount))
|
||||
} yield {
|
||||
val managementUrl = "/banks/" + url(2) + "/accounts/" + url(4) + "/management"
|
||||
".navlink [href]" #> { managementUrl } &
|
||||
".navlink *" #> "Management" &
|
||||
".navlink [class+]" #> markIfSelected(managementUrl)
|
||||
}
|
||||
|
||||
if (url.size > 4) getManagement getOrElse eraseMenu
|
||||
else eraseMenu
|
||||
}
|
||||
|
||||
def item = {
|
||||
val attrs = S.prefixedAttrsToMetaData("a")
|
||||
val name = S.attr("name").getOrElse("")
|
||||
val loc =
|
||||
for{
|
||||
sitemap <- LiftRules.siteMap
|
||||
l <- new SiteMapSingleton().findAndTestLoc(name)
|
||||
} yield l
|
||||
|
||||
".navitem *" #>{
|
||||
loc.map(navItemSelector)
|
||||
}
|
||||
}
|
||||
|
||||
def navItemSelector(l : Loc[_]) = {
|
||||
".navlink [href]" #> l.calcDefaultHref &
|
||||
".navlink *" #> l.linkText &
|
||||
".navlink [class+]" #> markIfSelected(l.calcDefaultHref)
|
||||
}
|
||||
|
||||
def onlyOnSomePages = {
|
||||
val pages : List[String]= S.attr("pages").map(_.toString.split(",").toList).getOrElse(Nil)
|
||||
|
||||
val locs = pages.flatMap(page => (for{
|
||||
sitemap <- LiftRules.siteMap
|
||||
l <- new SiteMapSingleton().findAndTestLoc(page)
|
||||
} yield l))
|
||||
|
||||
val isPage = locs.map(l => {
|
||||
//hack due to deadline to fix / and /index being the same
|
||||
val currentPage = if(S.uri == "/") "/index" else S.uri
|
||||
(l.calcDefaultHref == currentPage)
|
||||
}).exists(_ == true)
|
||||
|
||||
if(isPage) item
|
||||
else "* *" #> ""
|
||||
}
|
||||
|
||||
def privilegeAdmin = {
|
||||
val url = S.uri.split("/", 0)
|
||||
|
||||
def hide = ".navitem *" #> ""
|
||||
|
||||
def getPrivilegeAdmin = for {
|
||||
bankAccount <- BankAccount(url(2), url(4))
|
||||
user <- OBPUser.currentUser
|
||||
if (user.hasOwnerPermission(bankAccount))
|
||||
loc <- new SiteMapSingleton().findAndTestLoc("Privilege Admin")
|
||||
} yield {
|
||||
".navitem *" #> {
|
||||
".navlink [href]" #> loc.calcDefaultHref &
|
||||
".navlink *" #> loc.linkText &
|
||||
".navlink [class+]" #> markIfSelected(loc.calcDefaultHref)
|
||||
}
|
||||
}
|
||||
|
||||
if(url.size > 4) getPrivilegeAdmin.getOrElse(hide) else hide
|
||||
}
|
||||
|
||||
def markIfSelected(href : String) : Box[String]= {
|
||||
val currentHref = S.uri
|
||||
if(href.equals(currentHref)) Full("selected")
|
||||
else Empty
|
||||
}
|
||||
|
||||
def listAccounts = {
|
||||
var accounts : List[(String, String)] = List()
|
||||
OBPUser.currentUser match {
|
||||
case Full(user) => Account.findAll.map(account => {
|
||||
val bankAccount = Account.toBankAccount(account)
|
||||
if(user.permittedViews(bankAccount).size != 0)
|
||||
accounts ::= (account.bankPermalink + "," + account.permalink, account.bankName + " - " + account.name)
|
||||
})
|
||||
case _ => Account.findAll.map(account =>
|
||||
if(account.anonAccess.is)
|
||||
accounts ::= (account.bankPermalink + "," + account.permalink, account.bankName + " - " + account.name)
|
||||
)
|
||||
}
|
||||
accounts ::= ("0","--> Choose an account")
|
||||
def redirect(selectValue : String) : JsCmd =
|
||||
{
|
||||
val bankAndaccount = selectValue.split(",",0)
|
||||
if(bankAndaccount.size==2)
|
||||
if (LocalStorage.correctBankAndAccount(bankAndaccount(0), bankAndaccount(1)))
|
||||
//TODO : the account may not has an public view, so this redirection would retun a 404
|
||||
//a better solution has to be found
|
||||
S.redirectTo("/banks/" + bankAndaccount(0) + "/accounts/" + bankAndaccount(1) +"/public")
|
||||
else
|
||||
_Noop
|
||||
else
|
||||
_Noop
|
||||
}
|
||||
def computeDefaultValue : Box[String] =
|
||||
{
|
||||
val url = S.uri.split("/",0)
|
||||
var output="0"
|
||||
if(url.size>4)
|
||||
output = url(2) + "," + url(4)
|
||||
Full(output)
|
||||
}
|
||||
"#accountList *" #> {
|
||||
computeDefaultValue match {
|
||||
case Full("postbank,tesobe") =>
|
||||
SHtml.ajaxSelect(accounts,computeDefaultValue,redirect _)
|
||||
case _ =>
|
||||
NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
149
MavLift/src/main/scala/code/snippet/OAuthAuthorisation.scala
Normal file
149
MavLift/src/main/scala/code/snippet/OAuthAuthorisation.scala
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
Open Bank Project
|
||||
|
||||
Copyright 2011,2012 TESOBE / Music Pictures Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Open Bank Project (http://www.openbankproject.com)
|
||||
Copyright 2011,2012 TESOBE / Music Pictures Ltd
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Everett Sochowski: everett AT tesobe DOT com
|
||||
Ayoub Benali : ayoub AT tesobe Dot com
|
||||
*/
|
||||
package code.snippet
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.http.Req
|
||||
import net.liftweb.http.GetRequest
|
||||
import net.liftweb.http.PostRequest
|
||||
import net.liftweb.http.LiftResponse
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.http.InMemoryResponse
|
||||
import net.liftweb.common.{Full,Empty}
|
||||
import net.liftweb.http.S
|
||||
import code.model.{Nonce, Consumer, Token}
|
||||
import net.liftweb.mapper.By
|
||||
import java.util.Date
|
||||
import java.net.{URLEncoder, URLDecoder}
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import javax.crypto.Mac
|
||||
import net.liftweb.util.Helpers
|
||||
import code.model.AppType._
|
||||
import code.model.TokenType
|
||||
import TokenType._
|
||||
import scala.compat.Platform
|
||||
import code.model.dataAccess.OBPUser
|
||||
import scala.xml.NodeSeq
|
||||
import net.liftweb.util.Helpers._
|
||||
|
||||
object OAuthAuthorisation {
|
||||
|
||||
// this method is specific to the authorization page ( where the user login to grant access
|
||||
// to the application (step 2))
|
||||
def tokenCheck =
|
||||
S.param("oauth_token") match {
|
||||
case Full(token) =>
|
||||
Token.find(By(Token.key,Helpers.urlDecode(token.toString)),By(Token.tokenType,TokenType.Request)) match {
|
||||
case Full(appToken) =>
|
||||
//check if the token is still valid
|
||||
if(appToken.isValid)
|
||||
if(OBPUser.loggedIn_?)
|
||||
{
|
||||
var verifier =""
|
||||
// if the user is logged in and no verifier have been generated
|
||||
if(appToken.verifier.isEmpty)
|
||||
{
|
||||
val randomVerifier = appToken.gernerateVerifier
|
||||
//the user is logged in so we have the current user
|
||||
val user = OBPUser.currentUser.get
|
||||
//FIXME: The whole snippet still use OBPUser, we must change it to the User trait
|
||||
appToken.userId(user.id_)
|
||||
if(appToken.save())
|
||||
verifier = randomVerifier
|
||||
}
|
||||
else
|
||||
verifier=appToken.verifier
|
||||
|
||||
// show the verifier if the application does not support
|
||||
// redirection
|
||||
if(appToken.callbackURL.is =="oob")
|
||||
"#verify-code *" #> verifier &
|
||||
"#errorMessage" #> "" &
|
||||
"#account" #> ""
|
||||
else
|
||||
{
|
||||
//redirect the user to the application with the verifier
|
||||
S.redirectTo(appToken.callbackURL+"?oauth_token="+token+
|
||||
"&oauth_verifier="+verifier)
|
||||
"#verifier" #> "you should be redirected"
|
||||
}
|
||||
}
|
||||
else
|
||||
//the user is not logged in so we show a login form
|
||||
Consumer.find(By(Consumer.id,appToken.consumerId)) match {
|
||||
case Full(consumer) => {
|
||||
"#applicationName" #> consumer.name &
|
||||
"#verifier" #>NodeSeq.Empty &
|
||||
"#errorMessage" #> NodeSeq.Empty &
|
||||
{
|
||||
".login [action]" #> OBPUser.loginPageURL &
|
||||
".forgot [href]" #> {
|
||||
val href = for {
|
||||
menu <- OBPUser.resetPasswordMenuLoc
|
||||
} yield menu.loc.calcDefaultHref
|
||||
|
||||
href getOrElse "#"
|
||||
} &
|
||||
".signup [href]" #>
|
||||
OBPUser.signUpPath.foldLeft("")(_ + "/" + _)
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
"#errorMessage" #> "Application not found" &
|
||||
"#userAccess" #> NodeSeq.Empty
|
||||
}
|
||||
else
|
||||
"#errorMessage" #> "Token expired" &
|
||||
"#userAccess" #> NodeSeq.Empty
|
||||
case _ =>
|
||||
"#errorMessage" #> "This token does not exist" &
|
||||
"#userAccess" #> NodeSeq.Empty
|
||||
}
|
||||
case _ =>
|
||||
"#errorMessage" #> "There is no Token"&
|
||||
"#userAccess" #> NodeSeq.Empty
|
||||
}
|
||||
|
||||
//looks for expired tokens and nonces and delete them
|
||||
def dataBaseCleaner : Unit = {
|
||||
import net.liftweb.util.Schedule
|
||||
import net.liftweb.mapper.By_<
|
||||
Schedule.schedule(dataBaseCleaner _, 1 hour)
|
||||
|
||||
val currentDate = new Date()
|
||||
|
||||
/*
|
||||
As in "wrong timestamp" function, 3 minutes is the timestamp limit where we accept
|
||||
requests. So this function will delete nonces which have a timestamp older than
|
||||
currentDate - 3 minutes
|
||||
*/
|
||||
val timeLimit = new Date(currentDate.getTime + 180000)
|
||||
|
||||
//delete expired tokens and nonces
|
||||
(Token.findAll(By_<(Token.expirationDate,currentDate)) ++ Nonce.findAll(By_<(Nonce.timestamp,timeLimit))).foreach(t => t.delete_!)
|
||||
}
|
||||
}
|
||||
@ -1,552 +0,0 @@
|
||||
/**
|
||||
Open Bank Project
|
||||
|
||||
Copyright 2011,2012 TESOBE / Music Pictures Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Open Bank Project (http://www.openbankproject.com)
|
||||
Copyright 2011,2012 TESOBE / Music Pictures Ltd
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Everett Sochowski: everett AT tesobe DOT com
|
||||
Ayoub Benali : ayoub AT tesobe Dot com
|
||||
*/
|
||||
package code.snippet
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.http.Req
|
||||
import net.liftweb.http.GetRequest
|
||||
import net.liftweb.http.PostRequest
|
||||
import net.liftweb.http.LiftResponse
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.http.InMemoryResponse
|
||||
import net.liftweb.common.{Full,Empty}
|
||||
import net.liftweb.http.S
|
||||
import code.model.{Nonce, Consumer, Token}
|
||||
import net.liftweb.mapper.By
|
||||
import java.util.Date
|
||||
import java.net.{URLEncoder, URLDecoder}
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import javax.crypto.Mac
|
||||
import net.liftweb.util.Helpers
|
||||
import code.model.AppType._
|
||||
import code.model.TokenType._
|
||||
import scala.compat.Platform
|
||||
import code.model.dataAccess.OBPUser
|
||||
import scala.xml.NodeSeq
|
||||
import net.liftweb.util.Helpers._
|
||||
|
||||
object OAuthHandshake extends RestHelper
|
||||
{
|
||||
serve
|
||||
{
|
||||
//Handling get request for a "request token"
|
||||
case Req("oauth" :: "initiate" :: Nil,_ ,PostRequest) =>
|
||||
{
|
||||
//Extract the OAuth parameters from the header and test if the request is valid
|
||||
var (httpCode, data, oAuthParameters) = validator("requestToken", "POST")
|
||||
//Test if the request is valid
|
||||
if(httpCode==200)
|
||||
{
|
||||
//Generate the token and secret
|
||||
val (token,secret) = generateTokenAndSecret(oAuthParameters.get
|
||||
("oauth_consumer_key").get)
|
||||
//Save the token that we have generated
|
||||
if(saveRequestToken(oAuthParameters,token, secret))
|
||||
data=("oauth_token="+token+"&oauth_token_secret="+
|
||||
secret+"&oauth_callback_confirmed=true").getBytes()
|
||||
}
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
//return an HTTP response
|
||||
Full(InMemoryResponse(data,headers,Nil,httpCode))
|
||||
}
|
||||
case Req("oauth" :: "token" :: Nil,_, PostRequest) =>
|
||||
{
|
||||
//Extract the OAuth parameters from the header and test if the request is valid
|
||||
var (httpCode, data, oAuthParameters) = validator("authorizationToken", "POST")
|
||||
//Test if the request is valid
|
||||
if(httpCode==200)
|
||||
{
|
||||
//Generate the token and secret
|
||||
val (token,secret) = generateTokenAndSecret(oAuthParameters.get
|
||||
("oauth_consumer_key").get)
|
||||
//Save the token that we have generated
|
||||
if(saveAuthorizationToken(oAuthParameters,token, secret))
|
||||
//remove the request token so the application could not exchange it
|
||||
//again to get an other access token
|
||||
Token.find(By(Token.key,oAuthParameters.get("oauth_token").get)) match {
|
||||
case Full(requestToken) => requestToken.delete_!
|
||||
case _ => None
|
||||
}
|
||||
|
||||
data=("oauth_token="+token+"&oauth_token_secret="+secret).getBytes()
|
||||
}
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
//return an HTTP response
|
||||
Full(InMemoryResponse(data,headers,Nil,httpCode))
|
||||
}
|
||||
}
|
||||
|
||||
//Check if the request (access toke or request token) is valid and return a tuple
|
||||
def validator(requestType : String, httpMethod : String) =
|
||||
{
|
||||
//return a Map containing the OAuth parameters : oauth_prameter -> value
|
||||
def getAllParameters =
|
||||
{
|
||||
//Convert the string containing the list of OAuth parameters to a Map
|
||||
def toMap(parametersList : String) =
|
||||
{
|
||||
//transform the string "oauth_prameter="value""
|
||||
//to a tuple (oauth_parameter,Decoded(value))
|
||||
def dynamicListExtract(input: String) =
|
||||
{
|
||||
val oauthPossibleParameters = List("oauth_consumer_key","oauth_nonce",
|
||||
"oauth_signature_method", "oauth_timestamp","oauth_version",
|
||||
"oauth_signature","oauth_callback", "oauth_token","oauth_verifier")
|
||||
|
||||
if (input contains "=") {
|
||||
val split = input.split("=",2)
|
||||
val parameterValue = URLDecoder.decode(split(1)).replace("\"","")
|
||||
//add only OAuth parameters and not empty
|
||||
if(oauthPossibleParameters.contains(split(0)) && ! parameterValue.isEmpty)
|
||||
Some(split(0),parameterValue) // return key , value
|
||||
else
|
||||
None
|
||||
}
|
||||
else
|
||||
None
|
||||
}
|
||||
|
||||
Map(parametersList.split(",").flatMap(dynamicListExtract _): _*)
|
||||
}
|
||||
|
||||
S.request match
|
||||
{
|
||||
case Full(a) => a.header("Authorization") match
|
||||
{
|
||||
case Full(parameters) => toMap(parameters)
|
||||
case _ => Map(("",""))
|
||||
}
|
||||
case _ => Map(("",""))
|
||||
}
|
||||
}
|
||||
//return true if the authorization header has a duplicated parameter
|
||||
def duplicatedParameters =
|
||||
{
|
||||
var output=false
|
||||
val authorizationParameters = S.request.get.header("Authorization").get.split(",")
|
||||
|
||||
//count the iterations of a parameter in the authorization header
|
||||
def countPram(parameterName : String, parametersArray :Array[String] )={
|
||||
var i = 0
|
||||
parametersArray.foreach(t => {if (t.split("=")(0) == parameterName) i+=1})
|
||||
i
|
||||
}
|
||||
|
||||
//return true if on of the Authorization header parameter is present more than one time
|
||||
authorizationParameters.foreach(t => {
|
||||
if(countPram(t.split("=")(0),authorizationParameters)>1 && !output)
|
||||
output=true
|
||||
})
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
def suportedOAuthVersion(OAuthVersion : Option[String]) : Boolean = {
|
||||
//auth_version is OPTIONAL. If present, MUST be set to "1.0".
|
||||
OAuthVersion match
|
||||
{
|
||||
case Some(a) => a=="1" || a=="1.0"
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
def wrongTimestamp(requestTimestamp : Date) = {
|
||||
val currentTime = Platform.currentTime
|
||||
val timeRange : Long = 180000 //3 minutes
|
||||
//check if the timestamp is positive and in the time range
|
||||
requestTimestamp.getTime < 0 || requestTimestamp.before(new Date(currentTime - timeRange)) || requestTimestamp.after(new Date(currentTime + timeRange))
|
||||
}
|
||||
|
||||
def alReadyUsedNonce(parameters : Map[String, String]) = {
|
||||
|
||||
/*The nonce value MUST be unique across all requests with the
|
||||
same timestamp, client credentials, and token combinations.
|
||||
*/
|
||||
val token = parameters.get("oauth_token") getOrElse ""
|
||||
|
||||
Nonce.findAll(By(Nonce.value,parameters.get("oauth_nonce").get), By(Nonce.tokenKey, token),
|
||||
By(Nonce.consumerkey,parameters.get("oauth_consumer_key").get),
|
||||
By(Nonce.timestamp, new Date(parameters.get("oauth_timestamp").get.toLong))).length !=0
|
||||
}
|
||||
def registeredApplication(consumerKey : String ) : Boolean =
|
||||
{
|
||||
Consumer.find(By(Consumer.key,consumerKey)) match
|
||||
{
|
||||
case Full(application) => application.isActive
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
def correctSignature(OAuthparameters : Map[String, String], httpMethod : String) =
|
||||
{
|
||||
//Normalize an encode the request parameters as explained in Section 3.4.1.3.2
|
||||
//of OAuth 1.0 specification (http://tools.ietf.org/html/rfc5849)
|
||||
def generateOAuthParametersString(OAuthparameters : Map[String, String]) : String =
|
||||
{
|
||||
def sortParam( keyAndValue1 : (String, String), keyAndValue2 : (String, String))= keyAndValue1._1.compareTo(keyAndValue2._1) < 0
|
||||
|
||||
var parameters =""
|
||||
|
||||
//sort the parameters by name
|
||||
OAuthparameters.toList.sort(sortParam _).foreach(t =>
|
||||
if(t._1 != "oauth_signature")
|
||||
parameters += URLEncoder.encode(t._1,"UTF-8")+"%3D"+
|
||||
URLEncoder.encode(t._2,"UTF-8")+"%26"
|
||||
)
|
||||
parameters = parameters.dropRight(3) //remove the "&" encoded sign
|
||||
parameters
|
||||
}
|
||||
|
||||
//prepare the base string
|
||||
var baseString = httpMethod+"&"+URLEncoder.encode(S.hostAndPath,"UTF-8")+"&"
|
||||
baseString+= generateOAuthParametersString(OAuthparameters)
|
||||
|
||||
//get the key to sign
|
||||
val comsumer = Consumer.find(By(Consumer.key,OAuthparameters.
|
||||
get("oauth_consumer_key").get)).get
|
||||
var secret= comsumer.secret.toString()
|
||||
OAuthparameters.get("oauth_token") match
|
||||
{
|
||||
case Some(tokenKey) => Token.find(By(Token.key,tokenKey)) match {
|
||||
case Full(token) => secret+= "&" +token.secret.toString()
|
||||
case _ => None
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
|
||||
//signing process
|
||||
var m = Mac.getInstance("HmacSHA256");
|
||||
m.init(new SecretKeySpec(secret.getBytes(),"HmacSHA256"))
|
||||
val calculatedSignature = Helpers.base64Encode(m.doFinal(baseString.getBytes)).dropRight(1) //remove the "=" added by the base64Encode method
|
||||
|
||||
|
||||
calculatedSignature==OAuthparameters.get("oauth_signature").get
|
||||
}
|
||||
|
||||
//check if the token exists and is still valid
|
||||
def validToken(tokenKey : String, verifier : String) =
|
||||
{
|
||||
Token.find(By(Token.key, tokenKey)) match
|
||||
{
|
||||
case Full(token) => if(token.expirationDate.compareTo(new Date(
|
||||
Platform.currentTime)) == 1 && token.verifier==verifier)
|
||||
true
|
||||
else
|
||||
false
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
def validToken2(tokenKey : String) =
|
||||
{
|
||||
Token.find(By(Token.key, tokenKey)) match
|
||||
{
|
||||
case Full(token) => if(token.expirationDate.compareTo(new Date(
|
||||
Platform.currentTime)) == 1)
|
||||
true
|
||||
else
|
||||
false
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
//check if the all the necessary OAuth parameters are present regarding
|
||||
//the request type
|
||||
def enoughtOauthParameters(parameters : Map[String, String], requestType : String) : Boolean =
|
||||
{
|
||||
val parametersBase = List("oauth_consumer_key","oauth_nonce","oauth_signature_method",
|
||||
"oauth_timestamp", "oauth_signature")
|
||||
|
||||
if (parameters.size < 6)
|
||||
false
|
||||
else if(requestType == "requestToken")
|
||||
("oauth_callback" :: parametersBase).toSet.subsetOf(parameters.keySet)
|
||||
else if(requestType=="authorizationToken")
|
||||
("oauth_token" :: "oauth_verifier" :: parametersBase).toSet.subsetOf(parameters.keySet)
|
||||
else if(requestType=="protectedResource")
|
||||
("oauth_token" :: parametersBase).toSet.subsetOf(parameters.keySet)
|
||||
else
|
||||
false
|
||||
}
|
||||
|
||||
var data =""
|
||||
var httpCode : Int = 500
|
||||
|
||||
var parameters = getAllParameters
|
||||
|
||||
//does all the OAuth parameters are presents?
|
||||
if(! enoughtOauthParameters(parameters,requestType))
|
||||
{
|
||||
data = "One or several parameters are missing"
|
||||
httpCode = 400
|
||||
}
|
||||
//no parameter exists more than one times
|
||||
else if (duplicatedParameters)
|
||||
{
|
||||
data = "Duplicated protocol parameters"
|
||||
httpCode = 400
|
||||
}
|
||||
//valid OAuth
|
||||
else if(!suportedOAuthVersion(parameters.get("oauth_version")))
|
||||
{
|
||||
data = "OAuth version not supported"
|
||||
httpCode = 400
|
||||
}
|
||||
//supported signature method
|
||||
else if (parameters.get("oauth_signature_method").get.toLowerCase()!="hmac-sha256")
|
||||
{
|
||||
data = "Unsupported signature method"
|
||||
httpCode = 400
|
||||
}
|
||||
//check if the application is registered and active
|
||||
else if(! registeredApplication(parameters.get("oauth_consumer_key").get))
|
||||
{
|
||||
data = "Invalid client credentials"
|
||||
httpCode = 401
|
||||
}
|
||||
//valid timestamp
|
||||
else if(wrongTimestamp(new Date(parameters.get("oauth_timestamp").get.toLong)))
|
||||
{
|
||||
data = "wrong timestamps"
|
||||
httpCode = 400
|
||||
}
|
||||
//unused nonce
|
||||
else if (alReadyUsedNonce(parameters))
|
||||
{
|
||||
data = "Nonce already used"
|
||||
httpCode = 401
|
||||
}
|
||||
//In the case OAuth authorization token request, check if the token is still valid and the verifier is correct
|
||||
else if(requestType=="authorizationToken" && !validToken(parameters.get("oauth_token").get, parameters.get("oauth_verifier").get))
|
||||
{
|
||||
data = "Invalid or expired token"
|
||||
httpCode = 401
|
||||
}
|
||||
//In the case protected resource access request, check if the token is still valid
|
||||
else if (requestType=="protectedResource" &&
|
||||
! validToken2(parameters.get("oauth_token").get))
|
||||
{
|
||||
data = "Invalid or expired token"
|
||||
httpCode = 401
|
||||
}
|
||||
//checking if the signature is correct
|
||||
else if(! correctSignature(parameters, httpMethod))
|
||||
{
|
||||
data = "Invalid signature"
|
||||
httpCode = 401
|
||||
}
|
||||
else
|
||||
httpCode = 200
|
||||
|
||||
(httpCode, data.getBytes(), parameters)
|
||||
}
|
||||
private def generateTokenAndSecret(ConsumerKey : String) =
|
||||
{
|
||||
import java.util.UUID._
|
||||
|
||||
// generate random string
|
||||
val token_data = ConsumerKey + randomUUID().toString() + Helpers.randomString(20)
|
||||
//use HmacSHA256 to compute the token
|
||||
val m = Mac.getInstance("HmacSHA256");
|
||||
m.init(new SecretKeySpec(token_data.getBytes(),"HmacSHA256"))
|
||||
val token = Helpers.base64Encode(m.doFinal(token_data.getBytes)).dropRight(1)
|
||||
|
||||
// generate random string
|
||||
val secret_data = ConsumerKey + randomUUID().toString() + Helpers.randomString(20) + token
|
||||
//use HmacSHA256 to compute the token
|
||||
val n = Mac.getInstance("HmacSHA256");
|
||||
n.init(new SecretKeySpec(token_data.getBytes(),"HmacSHA256"))
|
||||
val secret = Helpers.base64Encode(n.doFinal(token_data.getBytes)).dropRight(1)
|
||||
|
||||
(token,secret)
|
||||
}
|
||||
private def saveRequestToken(oAuthParameters : Map[String, String], tokenKey : String, tokenSecret : String) =
|
||||
{
|
||||
import code.model.{Nonce, Token, TokenType}
|
||||
|
||||
val nonce = Nonce.create
|
||||
nonce.consumerkey(oAuthParameters.get("oauth_consumer_key").get)
|
||||
nonce.timestamp(new Date(oAuthParameters.get("oauth_timestamp").get.toLong))
|
||||
nonce.value(oAuthParameters.get("oauth_nonce").get)
|
||||
val nonceSaved = nonce.save()
|
||||
|
||||
val token = Token.create
|
||||
token.tokenType(TokenType.Request)
|
||||
Consumer.find(By(Consumer.key,oAuthParameters.get("oauth_consumer_key").get)) match
|
||||
{
|
||||
case Full(consumer) => token.consumerId(consumer.id)
|
||||
case _ => None
|
||||
}
|
||||
token.key(tokenKey)
|
||||
token.secret(tokenSecret)
|
||||
if(! oAuthParameters.get("oauth_callback").get.isEmpty)
|
||||
token.callbackURL(URLDecoder.decode(oAuthParameters.get("oauth_callback").get,"UTF-8"))
|
||||
else
|
||||
token.callbackURL("oob")
|
||||
val currentTime = Platform.currentTime
|
||||
val tokenDuration : Long = 1800000 //the duration is 30 minutes TODO: 300000 in production mode
|
||||
token.duration(tokenDuration)
|
||||
token.expirationDate(new Date(currentTime+tokenDuration))
|
||||
token.insertDate(new Date(currentTime))
|
||||
val tokenSaved = token.save()
|
||||
|
||||
nonceSaved && tokenSaved
|
||||
}
|
||||
private def saveAuthorizationToken(oAuthParameters : Map[String, String], tokenKey : String, tokenSecret : String) =
|
||||
{
|
||||
import code.model.{Nonce, Token, TokenType}
|
||||
|
||||
val nonce = Nonce.create
|
||||
nonce.consumerkey(oAuthParameters.get("oauth_consumer_key").get)
|
||||
nonce.timestamp(new Date(oAuthParameters.get("oauth_timestamp").get.toLong))
|
||||
nonce.tokenKey(oAuthParameters.get("oauth_token").get)
|
||||
nonce.value(oAuthParameters.get("oauth_nonce").get)
|
||||
val nonceSaved = nonce.save()
|
||||
|
||||
val token = Token.create
|
||||
token.tokenType(TokenType.Access)
|
||||
Consumer.find(By(Consumer.key,oAuthParameters.get("oauth_consumer_key").get)) match
|
||||
{
|
||||
case Full(consumer) => token.consumerId(consumer.id)
|
||||
case _ => None
|
||||
}
|
||||
Token.find(By(Token.key, oAuthParameters.get("oauth_token").get)) match {
|
||||
case Full(requestToken) => token.userId(requestToken.userId)
|
||||
case _ => None
|
||||
}
|
||||
token.key(tokenKey)
|
||||
token.secret(tokenSecret)
|
||||
val currentTime = Platform.currentTime
|
||||
val tokenDuration : Long = 86400000 //the duration is 1 day
|
||||
token.duration(tokenDuration)
|
||||
token.expirationDate(new Date(currentTime+tokenDuration))
|
||||
token.insertDate(new Date(currentTime))
|
||||
val tokenSaved = token.save()
|
||||
|
||||
nonceSaved && tokenSaved
|
||||
}
|
||||
|
||||
// this method is specific to the authorization page ( where the user login to grant access
|
||||
// to the application (step 2))
|
||||
def tokenCheck =
|
||||
S.param("oauth_token") match
|
||||
{
|
||||
case Full(token) =>
|
||||
Token.find(By(Token.key,token.toString)) match
|
||||
{
|
||||
case Full(appToken) =>
|
||||
//check if the token is still valid
|
||||
if(appToken.expirationDate.compareTo(new Date(Platform.currentTime)) == 1)
|
||||
if(OBPUser.loggedIn_?)
|
||||
{
|
||||
var verifier =""
|
||||
// if the user is logged in and non verifier have been generated
|
||||
if(appToken.verifier.isEmpty)
|
||||
{
|
||||
val randomVerifier = Helpers.base64Encode(Helpers.randomString(20).getBytes()).dropRight(1)
|
||||
appToken.verifier(randomVerifier)
|
||||
appToken.userId(OBPUser.currentUserId.get.toLong)
|
||||
if(appToken.save())
|
||||
verifier = randomVerifier
|
||||
}
|
||||
else
|
||||
verifier=appToken.verifier
|
||||
|
||||
// show the verifier if the application does not support
|
||||
// redirection
|
||||
if(Token.callbackURL=="oob")
|
||||
"#verifier " #> verifier
|
||||
else
|
||||
{
|
||||
//redirect the user to the application with the verifier
|
||||
S.redirectTo(appToken.callbackURL+"?oauth_token="+token+
|
||||
"&oauth_verifier="+verifier)
|
||||
"#verifier" #> "you should be redirected"
|
||||
}
|
||||
}
|
||||
else
|
||||
//the user is not logged in so we show a login form
|
||||
Consumer.find(By(Consumer.id,appToken.consumerId)) match
|
||||
{
|
||||
case Full(consumer) =>
|
||||
{
|
||||
"#applicationName" #> consumer.name &
|
||||
"#verifier" #>NodeSeq.Empty &
|
||||
"#errorMessage" #> NodeSeq.Empty &
|
||||
{
|
||||
".login [action]" #> OBPUser.loginPageURL &
|
||||
".forgot [href]" #>
|
||||
{
|
||||
val href = for {
|
||||
menu <- OBPUser.resetPasswordMenuLoc
|
||||
} yield menu.loc.calcDefaultHref
|
||||
href getOrElse "#"
|
||||
} &
|
||||
".signup [href]" #>
|
||||
OBPUser.signUpPath.foldLeft("")(_ + "/" + _)
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
{
|
||||
"#errorMessage" #> "Application not found" &
|
||||
"#userAccess" #> NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
"#errorMessage" #> "Token expired" &
|
||||
"#userAccess" #> NodeSeq.Empty
|
||||
}
|
||||
case _ =>
|
||||
{
|
||||
"#errorMessage" #> "This token does not exist" &
|
||||
"#userAccess" #> NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
{
|
||||
"#errorMessage" #> "There is no Token"&
|
||||
"#userAccess" #> NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
|
||||
//looks for expired tokens and nonces and delete them
|
||||
def dataBaseCleaner : Unit =
|
||||
{
|
||||
import net.liftweb.util.Schedule
|
||||
import net.liftweb.mapper.By_<
|
||||
Schedule.schedule(dataBaseCleaner _, 1 hour)
|
||||
|
||||
val currentDate = new Date()
|
||||
|
||||
/*
|
||||
As in "wrong timestamp" function, 3 minutes is the timestamp limit where we accept
|
||||
requests. So this function will delete nonces which have a timestamp older than
|
||||
currentDate - 3 minutes
|
||||
*/
|
||||
val timeLimit = new Date(currentDate.getTime + 180000)
|
||||
|
||||
//delete expired tokens and nonces
|
||||
(Token.findAll(By_<(Token.expirationDate,currentDate)) ++ Nonce.findAll(By_<(Nonce.timestamp,timeLimit))).foreach(t => t.delete_!)
|
||||
}
|
||||
}
|
||||
@ -1,488 +0,0 @@
|
||||
/**
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
|
||||
*/
|
||||
package com.tesobe.utils {
|
||||
|
||||
import code.actors.EnvelopeInserter
|
||||
import net.liftweb.http._
|
||||
import net.liftweb.http.rest._
|
||||
import net.liftweb.json.JsonDSL._
|
||||
import net.liftweb.json.Printer._
|
||||
import net.liftweb.json.Extraction._
|
||||
import net.liftweb.json.JsonAST._
|
||||
import java.util.Calendar
|
||||
import net.liftweb.common.Failure
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.common.Empty
|
||||
import net.liftweb.mongodb._
|
||||
import net.liftweb.json.JsonAST.JString
|
||||
import com.mongodb.casbah.Imports._
|
||||
import _root_.java.math.MathContext
|
||||
import org.bson.types._
|
||||
import org.joda.time.{DateTime, DateTimeZone}
|
||||
import java.util.regex.Pattern
|
||||
import _root_.net.liftweb.common._
|
||||
import _root_.net.liftweb.util._
|
||||
import _root_.net.liftweb.http._
|
||||
import _root_.net.liftweb.mapper._
|
||||
import _root_.net.liftweb.util.Helpers._
|
||||
import _root_.net.liftweb.sitemap._
|
||||
import _root_.scala.xml._
|
||||
import _root_.net.liftweb.http.S._
|
||||
import _root_.net.liftweb.http.RequestVar
|
||||
import _root_.net.liftweb.util.Helpers._
|
||||
import _root_.net.liftweb.common.Full
|
||||
import net.liftweb.mongodb.{Skip, Limit}
|
||||
import _root_.net.liftweb.http.S._
|
||||
import _root_.net.liftweb.mapper.view._
|
||||
import com.mongodb._
|
||||
import code.model.dataAccess.{ Account, OBPEnvelope, OBPUser }
|
||||
import code.model.dataAccess.HostedAccount
|
||||
import code.model.dataAccess.LocalStorage
|
||||
import code.model.traits.ModeratedTransaction
|
||||
import code.model.traits.View
|
||||
import code.model.implementedTraits.View
|
||||
import code.model.dataAccess.OBPEnvelope._
|
||||
import code.model.traits.BankAccount
|
||||
import code.model.implementedTraits.Anonymous
|
||||
import code.model.traits.Bank
|
||||
import code.model.traits.User
|
||||
import java.util.Date
|
||||
import code.snippet.OAuthHandshake._
|
||||
import code.model.traits.ModeratedBankAccount
|
||||
|
||||
object OBPRest extends RestHelper with Loggable {
|
||||
|
||||
val dateFormat = ModeratedTransaction.dateFormat
|
||||
private def getUser(httpCode : Int, tokenID : Box[String]) : Box[OBPUser] =
|
||||
if(httpCode==200)
|
||||
{
|
||||
import code.model.Token
|
||||
Token.find(By(Token.key, tokenID.get)) match {
|
||||
case Full(token) => OBPUser.find(By(OBPUser.id, token.userId))
|
||||
case _ => Empty
|
||||
}
|
||||
}
|
||||
else
|
||||
Empty
|
||||
|
||||
serve("obp" / "v1.0" prefix {
|
||||
|
||||
case Nil JsonGet json => {
|
||||
|
||||
def gitCommit : String = {
|
||||
val commit = tryo{
|
||||
val properties = new java.util.Properties()
|
||||
properties.load(getClass().getClassLoader().getResourceAsStream("git.properties"))
|
||||
properties.getProperty("git.commit.id", "")
|
||||
}
|
||||
commit getOrElse ""
|
||||
}
|
||||
|
||||
val apiDetails = {
|
||||
("api" ->
|
||||
("version" -> "1.0") ~
|
||||
("git_commit" -> gitCommit) ~
|
||||
("hosted_by" ->
|
||||
("organisation" -> "TESOBE") ~
|
||||
("email" -> "contact@tesobe.com") ~
|
||||
("phone" -> "+49 (0)30 8145 3994"))) ~
|
||||
("links" ->
|
||||
("rel" -> "banks") ~
|
||||
("href" -> "/banks") ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> "Returns a list of banks supported on this server"))
|
||||
}
|
||||
|
||||
JsonResponse(apiDetails)
|
||||
}
|
||||
|
||||
case bankAlias :: "accounts" :: accountAlias :: "transactions" :: viewName :: Nil JsonGet json => {
|
||||
import code.snippet.OAuthHandshake._
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
|
||||
def asInt(s: Box[String], default: Int): Int = {
|
||||
s match {
|
||||
case Full(str) => tryo { str.toInt } getOrElse default
|
||||
case _ => default
|
||||
}
|
||||
}
|
||||
val bankAccount = BankAccount(bankAlias, accountAlias)
|
||||
val limit = asInt(json.header("obp_limit"), 50)
|
||||
val offset = asInt(json.header("obp_offset"), 0)
|
||||
/**
|
||||
* sortBy is currently disabled as it would open up a security hole:
|
||||
*
|
||||
* sortBy as currently implemented will take in a parameter that searches on the mongo field names. The issue here
|
||||
* is that it will sort on the true value, and not the moderated output. So if a view is supposed to return an alias name
|
||||
* rather than the true value, but someone uses sortBy on the other bank account name/holder, not only will the returned data
|
||||
* have the wrong order, but information about the true account holder name will be exposed due to its position in the sorted order
|
||||
*
|
||||
* This applies to all fields that can have their data concealed... which in theory will eventually be most/all
|
||||
*
|
||||
*/
|
||||
//val sortBy = json.header("obp_sort_by")
|
||||
val sortBy = None
|
||||
val sortDirection = OBPOrder(json.header("obp_sort_by"))
|
||||
val fromDate = tryo{dateFormat.parse(json.header("obp_from_date") getOrElse "")}.map(OBPFromDate(_))
|
||||
val toDate = tryo{dateFormat.parse(json.header("obp_to_date") getOrElse "")}.map(OBPToDate(_))
|
||||
|
||||
def getTransactions(bankAccount: BankAccount, view: View, user: Option[OBPUser]) = {
|
||||
if(bankAccount.authorisedAccess(view, user)) {
|
||||
val basicParams = List(OBPLimit(limit),
|
||||
OBPOffset(offset),
|
||||
OBPOrdering(sortBy, sortDirection))
|
||||
|
||||
val params : List[OBPQueryParam] = fromDate.toList ::: toDate.toList ::: basicParams
|
||||
bankAccount.getModeratedTransactions(params: _*)(view.moderate)
|
||||
} else Nil
|
||||
}
|
||||
|
||||
val response = for {
|
||||
bankAccount <- BankAccount(bankAlias, accountAlias)
|
||||
view <- View.fromUrl(viewName) //TODO: This will have to change if we implement custom view names for different accounts
|
||||
} yield {
|
||||
val ts = getTransactions(bankAccount, view, getUser(httpCode,oAuthParameters.get("oauth_token")))
|
||||
JsonResponse("transactions" -> ts.map(t => t.toJson(view)))
|
||||
}
|
||||
|
||||
response getOrElse InMemoryResponse(data, headers, Nil, 401) : LiftResponse
|
||||
}
|
||||
|
||||
case bankAlias :: "accounts" :: accountAlias :: "transactions" ::
|
||||
transactionID :: "transaction" :: viewName :: Nil JsonGet json => {
|
||||
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val user = getUser(httpCode,oAuthParameters.get("oauth_token"))
|
||||
|
||||
val moderatedTransactionAndView = for {
|
||||
bank <- Bank(bankAlias) ?~ { "bank " + bankAlias + " not found"} ~> 404
|
||||
account <- BankAccount(bankAlias, accountAlias) ?~ { "account " + accountAlias + " not found for bank"} ~> 404
|
||||
view <- View.fromUrl(viewName) ?~ { "view " + viewName + " not found for account"} ~> 404
|
||||
moderatedTransaction <- account.moderatedTransaction(transactionID, view, user) ?~ "view/transaction not authorised" ~> 401
|
||||
} yield {
|
||||
(moderatedTransaction, view)
|
||||
}
|
||||
|
||||
val links : List[JObject] = Nil
|
||||
|
||||
moderatedTransactionAndView.map(mtAndView => JsonResponse(("transaction" -> mtAndView._1.toJson(mtAndView._2)) ~
|
||||
("links" -> links)))
|
||||
}
|
||||
|
||||
case bankAlias :: "accounts" :: accountAlias :: "transactions" ::
|
||||
transactionID :: "comments" :: viewName :: Nil JsonGet json => {
|
||||
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val user = getUser(httpCode,oAuthParameters.get("oauth_token"))
|
||||
|
||||
val comments = for {
|
||||
bank <- Bank(bankAlias) ?~ { "bank " + bankAlias + " not found"} ~> 404
|
||||
account <- BankAccount(bankAlias, accountAlias) ?~ { "account " + accountAlias + " not found for bank"} ~> 404
|
||||
view <- View.fromUrl(viewName) ?~ { "view " + viewName + " not found for account"} ~> 404
|
||||
moderatedTransaction <- account.moderatedTransaction(transactionID, view, user) ?~ "view/transaction not authorised" ~> 401
|
||||
comments <- Box(moderatedTransaction.metadata).flatMap(_.comments) ?~ "transaction metadata not authorised" ~> 401
|
||||
} yield comments
|
||||
|
||||
val links : List[JObject] = Nil
|
||||
|
||||
comments.map(cs => JsonResponse(("comments" -> cs.map(_.toJson)) ~
|
||||
("links" -> links)))
|
||||
}
|
||||
|
||||
case bankPermalink :: "accounts" :: Nil JsonGet json => {
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
val user = getUser(httpCode,oAuthParameters.get("oauth_token"))
|
||||
|
||||
def bankAccountSet2JsonResponse(bankAccounts: Set[BankAccount]): LiftResponse = {
|
||||
val accJson = bankAccounts.map(bAcc => bAcc.overviewJson(user))
|
||||
JsonResponse(("accounts" -> accJson))
|
||||
}
|
||||
|
||||
Bank(bankPermalink) match {
|
||||
case Full(bank) =>
|
||||
{
|
||||
val availableAccounts = bank.accounts.filter(_.permittedViews(user).size!=0)
|
||||
if(availableAccounts.size!=0)
|
||||
bankAccountSet2JsonResponse(availableAccounts)
|
||||
else
|
||||
InMemoryResponse(data, headers, Nil, httpCode)
|
||||
}
|
||||
case _ => {
|
||||
val error = "bank " + bankPermalink + " not found"
|
||||
InMemoryResponse(error.getBytes(), headers, Nil, 404)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case bankAlias :: "accounts" :: accountAlias :: "account" :: viewName :: Nil JsonGet json => {
|
||||
val (httpCode, data, oAuthParameters) = validator("protectedResource", "GET")
|
||||
val headers = ("Content-type" -> "application/x-www-form-urlencoded") :: Nil
|
||||
val user = getUser(httpCode,oAuthParameters.get("oauth_token"))
|
||||
|
||||
case class ModeratedAccountAndViews(account: ModeratedBankAccount, views: Set[View])
|
||||
|
||||
val moderatedAccountAndViews = for {
|
||||
bank <- Bank(bankAlias) ?~ { "bank " + bankAlias + " not found"} ~> 404
|
||||
account <- BankAccount(bankAlias, accountAlias) ?~ { "account " + accountAlias + " not found for bank"} ~> 404
|
||||
view <- View.fromUrl(viewName) ?~ { "view " + viewName + " not found for account"} ~> 404
|
||||
moderatedAccount <- account.moderatedBankAccount(view, user) ?~ {"view/account not authorised"} ~> 401
|
||||
availableViews <- Full(account.permittedViews(user))
|
||||
} yield ModeratedAccountAndViews(moderatedAccount, availableViews)
|
||||
|
||||
def linkJson(view: View): JObject = {
|
||||
("rel" -> view.name) ~
|
||||
("href" -> { "/" + bankAlias + "/accounts/" + accountAlias + "/transactions/" + view.permalink }) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> view.description)
|
||||
}
|
||||
|
||||
def bankAccountMetaData(mv : ModeratedAccountAndViews) = {
|
||||
("views_available" -> mv.views.map(_.toJson)) ~
|
||||
("links" -> mv.views.map(linkJson))
|
||||
}
|
||||
|
||||
moderatedAccountAndViews.map(mv => JsonResponse("account" -> mv.account.toJson ~ bankAccountMetaData(mv)))
|
||||
}
|
||||
|
||||
case bankAlias :: "offices" :: Nil JsonGet json => {
|
||||
//TODO: An office model needs to be created
|
||||
val offices : List[JObject] = Nil
|
||||
JsonResponse("offices" -> offices)
|
||||
}
|
||||
|
||||
case bankAlias :: "bank" :: Nil JsonGet json => {
|
||||
|
||||
def links = {
|
||||
def accounts = {
|
||||
("rel" -> "accounts") ~
|
||||
("href" -> {"/" + bankAlias + "/accounts"}) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> "Get list of accounts available")
|
||||
}
|
||||
|
||||
def offices = {
|
||||
("rel" -> "offices") ~
|
||||
("href" -> {"/" + bankAlias + "/offices"}) ~
|
||||
("method" -> "GET") ~
|
||||
("title" -> "Get list of offices")
|
||||
}
|
||||
|
||||
List(accounts, offices)
|
||||
}
|
||||
|
||||
val bank = for {
|
||||
bank <- Bank(bankAlias) ?~ { "bank " + bankAlias + " not found"} ~> 404
|
||||
} yield bank
|
||||
|
||||
bank.map(b => JsonResponse(b.detailedJson ~ ("links" -> links)))
|
||||
}
|
||||
|
||||
case "banks" :: Nil JsonGet json => {
|
||||
JsonResponse("banks" -> Bank.toJson(Bank.all))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
serve {
|
||||
//a temporary way to add transaction via api for a single specific exception case. should be removed later.
|
||||
case "api" :: "tmp" :: "transactions" :: Nil JsonPost json => {
|
||||
val secretKey = S.param("secret")
|
||||
|
||||
def addMatchingTransactions(secret: String) = {
|
||||
val rawEnvelopes = json._1.children
|
||||
val envelopes = rawEnvelopes.flatMap(OBPEnvelope.fromJValue)
|
||||
val matchingEnvelopes = for {
|
||||
e <- envelopes
|
||||
bankName <- Props.get("exceptional_account_bankName")
|
||||
number <- Props.get("exceptional_account_number")
|
||||
kind <- Props.get("exceptional_account_kind")
|
||||
if(e.obp_transaction.get.this_account.get.bank.get.name.get == bankName)
|
||||
if(e.obp_transaction.get.this_account.get.number.get == number)
|
||||
if(e.obp_transaction.get.this_account.get.kind.get == kind)
|
||||
} yield e
|
||||
|
||||
val ipAddress = json._2.remoteAddr
|
||||
logger.info("Received " + rawEnvelopes.size +
|
||||
" json transactions to insert from ip address " + ipAddress)
|
||||
logger.info("Received " + matchingEnvelopes.size +
|
||||
" valid transactions to insert from ip address " + ipAddress)
|
||||
|
||||
/**
|
||||
* Using an actor to do insertions avoids concurrency issues with
|
||||
* duplicate transactions by processing transaction batches one
|
||||
* at a time. We'll have to monitor this to see if non-concurrent I/O
|
||||
* is too inefficient. If it is, we could break it up into one actor
|
||||
* per "Account".
|
||||
*/
|
||||
val createdEnvelopes = EnvelopeInserter !? (3 seconds, matchingEnvelopes)
|
||||
|
||||
createdEnvelopes match {
|
||||
case Full(l: List[JObject]) =>{
|
||||
if(matchingEnvelopes.size!=0)
|
||||
{
|
||||
Account.find(("number" -> Props.get("exceptional_account_number").getOrElse("")) ~
|
||||
("bankName" -> Props.get("exceptional_account_bankName").getOrElse("")) ~
|
||||
("kind" -> Props.get("exceptional_account_kind").getOrElse("")))
|
||||
match {
|
||||
case Full(account) => account.lastUpdate(new Date).save
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
JsonResponse(JArray(l))
|
||||
}
|
||||
case _ => InternalServerErrorResponse()
|
||||
}
|
||||
}
|
||||
|
||||
def valid(secret : String) = {
|
||||
val authorised = for (validSecret <- Props.get("exceptional_account_secret"))
|
||||
yield secret == validSecret
|
||||
|
||||
authorised getOrElse false
|
||||
}
|
||||
|
||||
secretKey match {
|
||||
case Full(s) => if(valid(s))
|
||||
addMatchingTransactions(s)
|
||||
else
|
||||
UnauthorizedResponse("wrong secret key")
|
||||
case _ => NotFoundResponse()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
serve {
|
||||
|
||||
/**
|
||||
* curl -i -H "Content-Type: application/json" -X POST -d '{
|
||||
* "obp_transaction":{
|
||||
* "this_account":{
|
||||
* "holder":"Music Pictures Limited",
|
||||
* "number":"123567",
|
||||
* "kind":"current",
|
||||
* "bank":{
|
||||
* "IBAN":"DE1235123612",
|
||||
* "national_identifier":"de.10010010",
|
||||
* "name":"Postbank"
|
||||
* }
|
||||
* },
|
||||
* "other_account":{
|
||||
* "holder":"Client 1",
|
||||
* "number":"123567",
|
||||
* "kind":"current",
|
||||
* "bank":{
|
||||
* "IBAN":"UK12222879",
|
||||
* "national_identifier":"uk.10010010",
|
||||
* "name":"HSBC"
|
||||
* }
|
||||
* },
|
||||
* "details":{
|
||||
* "type_en":"Transfer",
|
||||
* "type_de":"Überweisung",
|
||||
* "posted":{
|
||||
* "$dt":"2012-01-04T18:06:22.000Z"
|
||||
* },
|
||||
* "completed":{
|
||||
* "$dt":"2012-09-04T18:52:13.000Z"
|
||||
* },
|
||||
* "new_balance":{
|
||||
* "currency":"EUR",
|
||||
* "amount":"4323.45"
|
||||
* },
|
||||
* "value":{
|
||||
* "currency":"EUR",
|
||||
* "amount":"123.45"
|
||||
* },
|
||||
* "other_data":"9"
|
||||
* }
|
||||
* }
|
||||
* } ' http://localhost:8080/api/transactions
|
||||
*/
|
||||
case "api" :: "transactions" :: Nil JsonPost json => {
|
||||
|
||||
//
|
||||
// WARNING!
|
||||
//
|
||||
// If you have not configured a web server to restrict this URL
|
||||
// appropriately, anyone will be
|
||||
// able to post transactions to your database. This would obviously
|
||||
// be undesirable. So you should
|
||||
// definitely sort that out.
|
||||
//
|
||||
//
|
||||
|
||||
val rawEnvelopes = json._1.children
|
||||
|
||||
val envelopes = rawEnvelopes.map(e => {
|
||||
OBPEnvelope.fromJValue(e)
|
||||
})
|
||||
|
||||
val ipAddress = json._2.remoteAddr
|
||||
logger.info("Received " + rawEnvelopes.size +
|
||||
" json transactions to insert from ip address " + ipAddress)
|
||||
logger.info("Received " + envelopes.size +
|
||||
" valid transactions to insert from ip address " + ipAddress)
|
||||
|
||||
/**
|
||||
* Using an actor to do insertions avoids concurrency issues with
|
||||
* duplicate transactions by processing transaction batches one
|
||||
* at a time. We'll have to monitor this to see if non-concurrent I/O
|
||||
* is too inefficient. If it is, we could break it up into one actor
|
||||
* per "Account".
|
||||
*/
|
||||
val createdEnvelopes = EnvelopeInserter !? (3 seconds, envelopes.flatten)
|
||||
|
||||
createdEnvelopes match {
|
||||
case Full(l: List[JObject]) =>{
|
||||
if(envelopes.size!=0)
|
||||
{
|
||||
//we assume here that all the Envelopes concerns only one account
|
||||
val accountNumber = envelopes(0).get.obp_transaction.get.this_account.get.number.get
|
||||
val bankName = envelopes(0).get.obp_transaction.get.this_account.get.bank.get.name.get
|
||||
val accountKind = envelopes(0).get.obp_transaction.get.this_account.get.kind.get
|
||||
Account.find(("number" -> accountNumber) ~ ("bankName" -> bankName) ~ ("kind" -> accountKind))
|
||||
match {
|
||||
case Full(account) => account.lastUpdate(new Date).save
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
JsonResponse(JArray(l))
|
||||
}
|
||||
case _ => InternalServerErrorResponse()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
MavLift/src/main/scala/code/util/APIUtil.scala
Normal file
62
MavLift/src/main/scala/code/util/APIUtil.scala
Normal file
@ -0,0 +1,62 @@
|
||||
package code.util
|
||||
|
||||
import code.model.dataAccess.APIMetric
|
||||
import code.api.v1_2.ErrorMessage
|
||||
import net.liftweb.http.JsonResponse
|
||||
import net.liftweb.json.Extraction
|
||||
import net.liftweb.json.JsonAST.JValue
|
||||
import net.liftweb.http.js.JsExp
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.util.Helpers._
|
||||
import net.liftweb.http.S
|
||||
import net.liftweb.http.js.JE.JsRaw
|
||||
|
||||
object APIUtil {
|
||||
|
||||
implicit val formats = net.liftweb.json.DefaultFormats
|
||||
implicit def errorToJson(error: ErrorMessage): JValue = Extraction.decompose(error)
|
||||
|
||||
def httpMethod : String =
|
||||
S.request match {
|
||||
case Full(r) => r.request.method
|
||||
case _ => "GET"
|
||||
}
|
||||
|
||||
def isThereAnOAuthHeader : Boolean = {
|
||||
S.request match {
|
||||
case Full(a) => a.header("Authorization") match {
|
||||
case Full(parameters) => parameters.contains("OAuth")
|
||||
case _ => false
|
||||
}
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def logAPICall =
|
||||
APIMetric.createRecord.
|
||||
url(S.uriAndQueryString.getOrElse("")).
|
||||
date((now: TimeSpan)).
|
||||
save
|
||||
|
||||
def gitCommit : String = {
|
||||
val commit = tryo{
|
||||
val properties = new java.util.Properties()
|
||||
properties.load(getClass().getClassLoader().getResourceAsStream("git.properties"))
|
||||
properties.getProperty("git.commit.id", "")
|
||||
}
|
||||
commit getOrElse ""
|
||||
}
|
||||
|
||||
def noContentJsonResponse : JsonResponse =
|
||||
JsonResponse(JsRaw(""), Nil, Nil, 204)
|
||||
|
||||
def successJsonResponse(json: JsExp, httpCode : Int = 200) : JsonResponse =
|
||||
JsonResponse(json, Nil, Nil, httpCode)
|
||||
|
||||
def errorJsonResponse(message : String = "error", httpCode : Int = 400) : JsonResponse =
|
||||
JsonResponse(Extraction.decompose(ErrorMessage(message)), Nil, Nil, httpCode)
|
||||
|
||||
def oauthHeaderRequiredJsonResponce : JsonResponse =
|
||||
JsonResponse(Extraction.decompose(ErrorMessage("Authentication via OAuth is required")), Nil, Nil, 400)
|
||||
|
||||
}
|
||||
166
MavLift/src/main/webapp/connect.html
Normal file
166
MavLift/src/main/webapp/connect.html
Normal file
@ -0,0 +1,166 @@
|
||||
<!--
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
-->
|
||||
|
||||
<div id="main" class="lift:surround?with=default;at=content">
|
||||
<p>
|
||||
You can connect to your bank account using this page.
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
Once an account is connected you can view your transaction data here - and can share the data with other people too.
|
||||
</p>
|
||||
<div class="lift:AccountRegistration.renderForm">
|
||||
<div class="lift:Msg?id=submissionMessage¬iceClass=submission">message</div>
|
||||
<form action="/connect" method="post" id="submitAccount" >
|
||||
<TABLE>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="2" >
|
||||
Please complete the information below so we can connect to your bank account.
|
||||
<a href="#registrationDetails"> *</a> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="bankList">Bank</label>
|
||||
</td>
|
||||
<td>
|
||||
<span id="bankListCol">
|
||||
<select>
|
||||
<option id="01"> post bank</option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="lift:Msg?id=bankError&errorClass=error">error</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="accountNumber">Account Number</label>
|
||||
</td>
|
||||
<td>
|
||||
<span id="accountNumberCol">
|
||||
<input type="text"/>
|
||||
</span>
|
||||
<span class="lift:Msg?id=accountNumberError&errorClass=error">error</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="accountPIN">PIN code</label>
|
||||
</td>
|
||||
<td>
|
||||
<span id="accountPINCol">
|
||||
<input type="password" />
|
||||
</span>
|
||||
<span class="lift:Msg?id=accountPINError&errorClass=error">error</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="accountName">Short name</label>
|
||||
<img src="/media/images/moreInfo.png" title="It will to determine the account URL and be used instead of the account number" alt="more info" class="moreInfoIcon"/>
|
||||
</td>
|
||||
<td>
|
||||
<span id="accountNameCol">
|
||||
<input type="text" />
|
||||
</span>
|
||||
<span class="lift:Msg?id=accountNameError&errorClass=error">error</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="accountLabel">Account description</label>
|
||||
<img src="/media/images/moreInfo.png" title="It will be shown on the top of each page"
|
||||
alt="more info" class="moreInfoIcon"/>
|
||||
</td>
|
||||
<td>
|
||||
<span id="accountLabelCol">
|
||||
<input type="text" />
|
||||
</span>
|
||||
<span class="lift:Msg?id=accountLabelError&errorClass=error">error</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="accountHolder">Holder Name</label>
|
||||
<img src="/media/images/moreInfo.png" title="The person who owns the account"
|
||||
alt="more info" class="moreInfoIcon"/>
|
||||
</td>
|
||||
<td>
|
||||
<span id="accountHolderCol">
|
||||
<input type="text" />
|
||||
</span>
|
||||
<span class="lift:Msg?id=accountHolderError&errorClass=error">error</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="accountKind">Account type</label>
|
||||
<img src="/media/images/moreInfo.png" title="current, checking, saving,etc."
|
||||
alt="more info" class="moreInfoIcon"/>
|
||||
</td>
|
||||
<td>
|
||||
<span id="accountKindCol">
|
||||
<input type="text" />
|
||||
</span>
|
||||
<span class="lift:Msg?id=accountKindError&errorClass=error">error</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Public view
|
||||
<img src="/media/images/moreInfo.png" title="Do you want to allow a public view on your account ?"
|
||||
alt="more info" class="moreInfoIcon"/>
|
||||
</td>
|
||||
<td>
|
||||
<span id="publicViewCol"></span>
|
||||
<span class="lift:Msg?id=publicViewError&errorClass=error">error</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" >
|
||||
<span id="registrationDetails">
|
||||
(*) : Your PIN code will be securely encrypted. We will not disclose your login data to anyone.
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" value="Submit" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</TABLE>
|
||||
</form>
|
||||
<div id="loginMsg"></div>
|
||||
</div>
|
||||
</div>
|
||||
105
MavLift/src/main/webapp/consumer-registration.html
Normal file
105
MavLift/src/main/webapp/consumer-registration.html
Normal file
@ -0,0 +1,105 @@
|
||||
<!--
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
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 / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
-->
|
||||
|
||||
<div id="main" class="lift:surround?with=default;at=content">
|
||||
<div class="lift:ConsumerRegistration.registerForm">
|
||||
<h1 class="register-header">Register to use the Open Bank API with your application:</h1>
|
||||
<div class="registration">
|
||||
<div>
|
||||
<span class="registration-error"></span>
|
||||
</div>
|
||||
<form class="register" method="post">
|
||||
<TABLE>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="2" >
|
||||
Please complete the information below so we can get an OAuth key and secret.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="appType">Application Type</label>
|
||||
</td>
|
||||
<td>
|
||||
<select name="app-type" id="appType">
|
||||
<option class="app-type-option"></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="appName">Application Name</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="app-name" id="appName"></input>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="appDev">Developer Email</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="app-developer" id="appDev"></input>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="appDesc">App Description</label>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="4" name="app-description" id="appDesc"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<input type="submit" value="Register" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</TABLE>
|
||||
</form>
|
||||
<div class="success">
|
||||
<h1 class="success-message">Thank you for registering to use the Open Bank API. Here is your developer information. Please save it in a secure location.</h1>
|
||||
<div class="user-generated">
|
||||
<div class="info">Application Name: <span class=app-name>ABC</span></div>
|
||||
<div class="info">Application Type: <span class=app-type>web</span></div>
|
||||
<div class="info">Description: <span class=app-description>ABCDEF</span></div>
|
||||
<div class="info">Developer Email: <span class=app-developer>abc@example.com</span></div>
|
||||
</div>
|
||||
<div class="server-generated">
|
||||
<div class="info">Consumer Key: <span class="auth-key">23432432432432</span></div>
|
||||
<div class="info">Consumer Secret: <span class="secret-key">3334543543543</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,4 +1,4 @@
|
||||
<!--
|
||||
<!--
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -30,5 +30,7 @@ Berlin 13359, Germany
|
||||
-->
|
||||
|
||||
<div id="main" class="lift:surround?with=default;at=content">
|
||||
Hello !
|
||||
<p>
|
||||
Welcome to The Open Bank Project API.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
<!--
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,27 +15,26 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
Ayoub Benali: ayoub AT tesobe DOT com
|
||||
Tim Kleinschmidt: tim@tesobe.com
|
||||
-->
|
||||
<div id="main" class="lift:surround?with=default;at=content">
|
||||
|
||||
*/
|
||||
package code.model.implementedTraits
|
||||
|
||||
import code.model.traits.{BankAccount,AccountOwner}
|
||||
|
||||
class AccountOwnerImpl(id_ : String, accountName : String, ownedBankAccounts: Set[BankAccount]) extends AccountOwner{
|
||||
def id = id_
|
||||
def name = accountName
|
||||
def bankAccounts = ownedBankAccounts
|
||||
}
|
||||
<link href="media/css/graphs.css" rel="stylesheet">
|
||||
<h1>Openbank Graphs</h1>
|
||||
<br>
|
||||
<script src="media/js/d3.v3.js"></script>
|
||||
<script src="media/js/graphs.js"></script>
|
||||
|
||||
</div>
|
||||
@ -1,4 +1,4 @@
|
||||
<!--
|
||||
<!--
|
||||
Open Bank Project - Transparency / Social Finance Web Application
|
||||
Copyright (C) 2011, 2012, TESOBE / Music Pictures Ltd
|
||||
|
||||
@ -15,14 +15,14 @@ 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 / Music Pictures Ltd
|
||||
Email: contact@tesobe.com
|
||||
TESOBE / Music Pictures Ltd
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
|
||||
This product includes software developed at
|
||||
TESOBE (http://www.tesobe.com/)
|
||||
by
|
||||
by
|
||||
Simon Redfern : simon AT tesobe DOT com
|
||||
Stefan Bethge : stefan AT tesobe DOT com
|
||||
Everett Sochowski : everett AT tesobe DOT com
|
||||
@ -62,32 +62,57 @@ Berlin 13359, Germany
|
||||
</form>
|
||||
</div>
|
||||
<!-- LOGGED IN -->
|
||||
<div class="lift:Login.loggedIn">
|
||||
<div class="profile-info">
|
||||
<div class="lift:Login.loggedIn">
|
||||
<div class="profile-info">
|
||||
Logged in as <span class="username">username@domain.com</span>
|
||||
<a href="" class="logout">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="nav">
|
||||
<ul>
|
||||
<li class="lift:Nav.item?name=Home navitem">
|
||||
<a class="navlink" href="#">Link name. Has class "selected" if it's the current page.</a>
|
||||
</li>
|
||||
<li class="lift:Nav.management navitem">
|
||||
<a class="navlink" href="#">Link name. Has class "selected" if it's the current page.</a>
|
||||
</li>
|
||||
<li class="lift:Nav.privilegeAdmin navitem">
|
||||
<a class="navlink" href="#">Link name. Has class "selected" if it's the current page.</a>
|
||||
</li>
|
||||
<span class="lift:Nav.views">
|
||||
<li class="navitem">
|
||||
<a class="navlink" href="#">Link name. Has class "selected" if it's the current page.</a>
|
||||
</li>
|
||||
</span>
|
||||
<li class="lift:Nav.onlyOnSomePages?pages=Home,Consumer%20Registration&name=Consumer%20Registration navitem">
|
||||
<a class="navlink" href="#">Link name. Has class "selected" if it's the current page.</a>
|
||||
</li>
|
||||
<li class="lift:Nav.onlyOnSomePages?pages=Home,Metrics&name=Metrics navitem">
|
||||
<a class="navlink" href="#">Link name. Has class "selected" if it's the current page.</a>
|
||||
</li>
|
||||
<li class="lift:Nav.onlyOnSomePages?pages=Home,Connect&name=Connect navitem">
|
||||
<a class="navlink" href="#">Link name. Has class "selected" if it's the current page.</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
<lift:bind name="content" />
|
||||
The main content gets bound here
|
||||
The main content gets bound here
|
||||
</div>
|
||||
|
||||
|
||||
<div id="footer">
|
||||
<p><a href="http://openbankproject.com">Open Bank Project</a> is ©2011-2012 <a href="http://tesobe.com">TESOBE</a> and distributed under the Apache 2.0 License.</p>
|
||||
<br/>
|
||||
<p><a href="http://openbankproject.com">Open Bank Project</a> is ©2011-2013 <a href="http://tesobe.com">TESOBE</a> and distributed under the Apache 2.0 License.</p>
|
||||
<br/>
|
||||
<p>
|
||||
<a href="http://www.facebook.com/pages/Open-Bank-Project/118851468190327">Facebook Page</a> |
|
||||
<a href="http://twitter.com/#!/OpenBankProject">Follow us on Twitter</a> |
|
||||
<a href="http://eviscape.com/profile/openbankproject/">Eviscape Profile</a> |
|
||||
<a href="http://polarize.it/polarize/openbankprojectdemoa_78828874370">Polarize it!</a> |
|
||||
<a href="https://github.com/OpenBankProject">Sources on Github</a> |
|
||||
<a href="https://github.com/OpenBankProject/OBP-API/wiki/OBP-Public-Facing-REST-API-V1.0-DRAFT">
|
||||
RESTful API
|
||||
</a>
|
||||
</p>
|
||||
<a href="http://www.facebook.com/pages/Open-Bank-Project/118851468190327">Facebook Page</a> |
|
||||
<a href="http://twitter.com/#!/OpenBankProject">Follow us on Twitter</a> |
|
||||
<a href="http://eviscape.com/profile/openbankproject/">Eviscape Profile</a> |
|
||||
<a href="http://polarize.it/polarize/openbankprojectdemoa_78828874370">Polarize it!</a> |
|
||||
<a href="https://github.com/OpenBankProject">Sources on Github</a> |
|
||||
<a href="https://github.com/OpenBankProject/OBP-API/wiki">API Documentation</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<a id="feedBack" href="http://polarize.it/polarize/openbankprojectdemoa_78828874370"></a>
|
||||
|
||||
@ -17,6 +17,7 @@ limitations under the License.
|
||||
*/
|
||||
import bootstrap.liftweb.Boot
|
||||
import scala.tools.nsc.MainGenericRunner
|
||||
import scala.sys._
|
||||
|
||||
object LiftConsole {
|
||||
def main(args : Array[String]) {
|
||||
@ -27,6 +28,6 @@ object LiftConsole {
|
||||
// Now run the MainGenericRunner to get your repl
|
||||
MainGenericRunner.main(args)
|
||||
// After the repl exits, then exit the scala script
|
||||
exit(0)
|
||||
sys.exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,8 +32,9 @@ import org.mortbay.jetty.Connector
|
||||
import org.mortbay.jetty.Server
|
||||
import org.mortbay.jetty.webapp.WebAppContext
|
||||
import org.mortbay.jetty.nio._
|
||||
import scala.sys._
|
||||
|
||||
object RunWebApp extends Application {
|
||||
object RunWebApp extends App {
|
||||
val server = new Server
|
||||
val scc = new SelectChannelConnector
|
||||
scc.setPort(8080)
|
||||
@ -57,7 +58,7 @@ object RunWebApp extends Application {
|
||||
} catch {
|
||||
case exc : Exception => {
|
||||
exc.printStackTrace()
|
||||
System.exit(100)
|
||||
sys.exit(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
30
MavLift/src/test/scala/code/api/API11Test.scala
Normal file
30
MavLift/src/test/scala/code/api/API11Test.scala
Normal file
@ -0,0 +1,30 @@
|
||||
package code.api.v1_1
|
||||
|
||||
import org.scalatest._
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
import dispatch._
|
||||
import code.api.test.{ServerSetup, APIResponse}
|
||||
|
||||
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class API1_1Test extends ServerSetup{
|
||||
|
||||
val v1_1Request = baseRequest / "obp" / "v1.1"
|
||||
|
||||
def getAPIInfo = {
|
||||
val request = v1_1Request
|
||||
makeGetRequest(request)
|
||||
}
|
||||
|
||||
/************************ the tests ************************/
|
||||
feature("base line URL works"){
|
||||
scenario("we get the api information") {
|
||||
Given("The user is not logged in")
|
||||
When("the request is sent")
|
||||
val reply = getAPIInfo
|
||||
Then("we should get a 200 created code")
|
||||
reply.code should equal (200)
|
||||
}
|
||||
}
|
||||
}
|
||||
5493
MavLift/src/test/scala/code/api/API12Test.scala
Normal file
5493
MavLift/src/test/scala/code/api/API12Test.scala
Normal file
File diff suppressed because it is too large
Load Diff
195
MavLift/src/test/scala/code/api/ServerSetup.scala
Normal file
195
MavLift/src/test/scala/code/api/ServerSetup.scala
Normal file
@ -0,0 +1,195 @@
|
||||
package code.api.test
|
||||
|
||||
import org.scalatest._
|
||||
import dispatch._
|
||||
import dispatch.liftjson.Js._
|
||||
import net.liftweb.json.NoTypeHints
|
||||
import net.liftweb.json.JsonAST.{JValue, JObject}
|
||||
import _root_.net.liftweb.json.Serialization.write
|
||||
import net.liftweb.common._
|
||||
import org.mortbay.jetty.Connector
|
||||
import org.mortbay.jetty.Server
|
||||
import org.mortbay.jetty.nio.SelectChannelConnector
|
||||
import org.mortbay.jetty.webapp.WebAppContext
|
||||
import net.liftweb.json.Serialization
|
||||
import org.junit.runner.RunWith
|
||||
import net.liftweb.mongodb._
|
||||
import net.liftweb.util.Props
|
||||
import code.model.dataAccess.{OBPUser, Privilege, HostedAccount, Account, HostedBank}
|
||||
import java.util.Date
|
||||
import _root_.net.liftweb.util._
|
||||
import Helpers._
|
||||
import org.bson.types.ObjectId
|
||||
import scala.util.Random._
|
||||
case class APIResponse(code: Int, body: JValue)
|
||||
|
||||
trait ServerSetup extends FeatureSpec
|
||||
with BeforeAndAfterAll with GivenWhenThen
|
||||
with ShouldMatchers with Loggable{
|
||||
|
||||
val server = ServerSetup
|
||||
|
||||
implicit val formats = Serialization.formats(NoTypeHints)
|
||||
|
||||
val h = new Http with thread.Safety
|
||||
val baseRequest = (:/(server.host, Integer.valueOf(server.port)))
|
||||
|
||||
|
||||
override def beforeAll() = {
|
||||
implicit val dateFormats = net.liftweb.json.DefaultFormats
|
||||
//create fake data for the tests
|
||||
|
||||
//fake banks
|
||||
val banks = for{i <- 0 until 3} yield {
|
||||
HostedBank.createRecord.
|
||||
name(randomString(5)).
|
||||
alias(randomString(5)).
|
||||
permalink(randomString(5)).
|
||||
save
|
||||
}
|
||||
|
||||
//fake bank accounts
|
||||
val accounts = banks.flatMap(bank => {
|
||||
for { i <- 0 until 2 } yield {
|
||||
Account.createRecord.
|
||||
balance(0).
|
||||
anonAccess(true).
|
||||
holder(randomString(4)).
|
||||
number(randomString(4)).
|
||||
kind(randomString(4)).
|
||||
name(randomString(4)).
|
||||
permalink(randomString(4)).
|
||||
bankID(new ObjectId(bank.id.get.toString)).
|
||||
label(randomString(4)).
|
||||
currency(randomString(4)).
|
||||
save
|
||||
}
|
||||
})
|
||||
|
||||
val hostedAccounts = accounts.map(account => {
|
||||
HostedAccount.create.accountID(account.id.get.toString).saveMe
|
||||
})
|
||||
|
||||
case class OBPTransactionWrapper(
|
||||
obp_transaction: OBPTransaction)
|
||||
|
||||
case class OBPTransaction(
|
||||
this_account: OBPAccount,
|
||||
other_account: OBPAccount,
|
||||
details: OBPDetails)
|
||||
|
||||
case class OBPAccount(
|
||||
holder: String,
|
||||
number: String,
|
||||
kind: String,
|
||||
bank: OBPBank)
|
||||
|
||||
case class OBPBank(
|
||||
IBAN: String,
|
||||
national_identifier: String,
|
||||
name: String)
|
||||
|
||||
case class OBPDetails(
|
||||
type_en: String,
|
||||
type_de: String,
|
||||
posted: Date,
|
||||
completed: Date,
|
||||
new_balance: OBPAmount,
|
||||
value: OBPAmount,
|
||||
label: String,
|
||||
other_data: String)
|
||||
|
||||
case class OBPAmount(
|
||||
currency: String,
|
||||
amount: String) {
|
||||
override def toString = "OBPAmount(" + currency + ",***)"
|
||||
}
|
||||
|
||||
//fake transactions
|
||||
val postTransaction = baseRequest / "api"/ "transactions"
|
||||
accounts.foreach(account => {
|
||||
val transactions =
|
||||
for{i <- 0 until 10} yield{
|
||||
val thisAccountBank = OBPBank("", "", account.bankName)
|
||||
val thisAccount = OBPAccount(account.holder.get, account.number.get, account.kind.get, thisAccountBank)
|
||||
val otherAccountBank = OBPBank("", "", randomString(5))
|
||||
val otherAccount = OBPAccount(randomString(5), randomString(5), randomString(5), otherAccountBank)
|
||||
val balance = OBPAmount(randomString(3), nextInt(100).toString)
|
||||
val value = OBPAmount(randomString(3), nextInt(100).toString)
|
||||
val details = OBPDetails(randomString(5), randomString(5), now, now, balance, value, randomString(10), "")
|
||||
val obpTransaction = OBPTransaction(thisAccount, otherAccount, details)
|
||||
OBPTransactionWrapper(obpTransaction)
|
||||
}
|
||||
makePostRequest(postTransaction, write(transactions))
|
||||
})
|
||||
specificSetup()
|
||||
}
|
||||
|
||||
//this method is to run a specific behavior before running each test class
|
||||
def specificSetup() = {
|
||||
}
|
||||
|
||||
override def afterAll() = {
|
||||
//drop the Database after the tests
|
||||
MongoDB.getDb(DefaultMongoIdentifier).map(_.dropDatabase())
|
||||
}
|
||||
/**
|
||||
this method do a post request given a URL, a JSON and an optional Headers Map
|
||||
*/
|
||||
def makePostRequest(req: Request, json: String = "", headers : Map[String,String] = Map()) : h.HttpPackage[APIResponse] = {
|
||||
val jsonReq = req << (json, "application/json") <:< headers
|
||||
val jsonHandler = jsonReq ># {json => json}
|
||||
h x jsonHandler{
|
||||
case (code, _, _, json) => APIResponse(code, json())
|
||||
}
|
||||
}
|
||||
|
||||
def makePutRequest(req: Request, json: String, headers : Map[String,String] = Map(("Content-type","application/json"))) : h.HttpPackage[APIResponse] = {
|
||||
val jsonReq = req <<< json <:< headers
|
||||
val jsonHandler = jsonReq ># {json => json}
|
||||
h x jsonHandler{
|
||||
case (code, _, _, json) => APIResponse(code, json())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this method do a post request given a URL
|
||||
*/
|
||||
def makeGetRequest(req: Request, headers : Map[String,String] = Map()) : h.HttpPackage[APIResponse] = {
|
||||
val jsonReq = req <:< headers
|
||||
val jsonHandler = jsonReq ># {json => json}
|
||||
h x jsonHandler{
|
||||
case (code, _, _, json) => APIResponse(code, json())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this method do a delete request given a URL
|
||||
*/
|
||||
def makeDeleteRequest(req: Request, headers : Map[String,String] = Map()) : h.HttpPackage[APIResponse] = {
|
||||
val jsonReq = (req <:< headers).DELETE
|
||||
val jsonHandler = jsonReq.>|
|
||||
h x jsonHandler{
|
||||
case (code, _, _, _) => APIResponse(code, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ServerSetup {
|
||||
|
||||
val host = "localhost"
|
||||
val port = 8000
|
||||
val server = new Server
|
||||
val scc = new SelectChannelConnector
|
||||
scc.setPort(port)
|
||||
server.setConnectors(Array(scc))
|
||||
|
||||
val context = new WebAppContext()
|
||||
context.setServer(server)
|
||||
context.setContextPath("/")
|
||||
context.setWar("src/main/webapp")
|
||||
|
||||
server.addHandler(context)
|
||||
|
||||
server.start()
|
||||
}
|
||||
53
README
53
README
@ -1,53 +0,0 @@
|
||||
# README
|
||||
|
||||
Welcome to the Open Bank Project API
|
||||
|
||||
## ABOUT
|
||||
|
||||
The API aims to provide a read only access to bank transaction in a simple and consistent structure by abstracting away the peculiarities of each banking system.
|
||||
|
||||
The API aims also to facilitate the data sharing with users, with several level of details in a secure way and to enhance the raw transactions with some metadata : comments, tags, pictures etc.
|
||||
|
||||
The API provides also OAuth 1.0 authentication.
|
||||
|
||||
## Document
|
||||
|
||||
Please refer to the [wiki](https://github.com/OpenBankProject/OBP-API/wiki) to see the API specification.
|
||||
|
||||
|
||||
## STATUS
|
||||
|
||||
For the moment some ready only API calls are implemented, by in the future there will be write API calls to post metadata like : comments, pictures, etc.
|
||||
|
||||
|
||||
## LICENSE
|
||||
|
||||
This project is dual licensed under the AGPL V3 (see NOTICE) and a commercial license from TESOBE
|
||||
Some files (OAuth related) are licensed under the Apache 2 license.
|
||||
|
||||
## SETUP
|
||||
|
||||
We recommend to use the Vagrant and Puppet scripts available [here](https://github.com/OpenBankProject/OBP-VM) to create a Virtual Box VM running the Open Bank Project API.
|
||||
|
||||
Other wise the project is using sbt or Maven 2 as a build tool.
|
||||
|
||||
----
|
||||
|
||||
To compile and run jetty, cd into the "MavLift" directory and run:
|
||||
|
||||
$ sbt
|
||||
...
|
||||
> compile
|
||||
> ~;container:start; container:reload /
|
||||
|
||||
(Note that you first have to start sbt and then on its console start jetty with the container:start task, otherwise it will exit immediately. More here: https://github.com/siasia/xsbt-web-plugin/wiki)
|
||||
|
||||
In OS X, sbt can be installed with $ sudo port install sbt
|
||||
|
||||
----
|
||||
|
||||
Alternatively, maven can also be used:
|
||||
|
||||
mvn jetty:run
|
||||
|
||||
You need to install MongoDB and create an empty database called "OBP006".
|
||||
Loading…
Reference in New Issue
Block a user