diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a037a80
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/.idea
+/vendor
+/config/Config.php
diff --git a/app/Barany/Command.php b/app/Barany/Command.php
new file mode 100644
index 0000000..faf640c
--- /dev/null
+++ b/app/Barany/Command.php
@@ -0,0 +1,6 @@
+addEntityResult('Barany\Model\Institution', 'i')
+ ->addFieldResult('i', 'id', 'id')
+ ->addFieldResult('i', 'name', 'name')
+ ->addFieldResult('i', 'code', 'code');
+ $sql = "SELECT i.id, i.name, i.code FROM institution i FORCE INDEX(name_idx) ORDER BY i.name ASC";
+ $query = $this
+ ->getEntityManager()
+ ->createNativeQuery($sql, $rsm);
+
+ /** @var Institution[] $institutions */
+ $institutions = $query->getResult();
+ $this->renderJson($institutions);
+ }
+
+ public function accounts($httpRequest) {
+//@todo: Use session uid
+$userId = 1;
+ /** @var User $user */
+ $user = $this->getEntityManager()->find('Barany\Model\User', $userId);
+ $this->renderJson($user ? $user->getAccounts() : []);
+ }
+
+ public function account($httpRequest) {
+ /** @var Account $account */
+ $account = $this->getEntityManager()->find('Barany\Model\Account', $httpRequest->account_id);
+
+ $plaidData = $this->getPlaidAccount($account);
+
+ $accounts = [];
+ foreach ($plaidData->body->accounts as $bankAccount) {
+ $accounts[$bankAccount->_id] = [
+ 'account' => $bankAccount,
+ 'transactions' => [],
+ ];
+ }
+ foreach ($plaidData->body->transactions as $transaction) {
+ $accounts[$transaction->_account]['transactions'][] = $transaction;
+ }
+
+ $this->renderJson(
+ [
+ 'institution' => $account->getInstitution()->toApi(),
+ 'accounts' => array_values($accounts),
+ ]
+ );
+ }
+
+ /**
+ * @param Account $account
+ * @return Response
+ */
+ private function getPlaidAccount(Account $account) {
+ $access_token = $account->getAccessToken();
+ $params = array_merge(
+ $this->getAppConfig()->getPlaidApiCredentials(),
+ array(
+ 'access_token' => $access_token,
+ )
+ );
+ $concatedParams = array();
+ foreach ($params as $k => $v) {
+ $concatedParams[] = "$k=$v";
+ }
+ $request = Request::get(
+ $this->getAppConfig()->getPlaidApiEndpoint() . 'connect?' . implode('&', $concatedParams),
+ 'application/json'
+ )
+ ->expects('application/json');
+
+ return $request->send();
+ }
+}
\ No newline at end of file
diff --git a/app/Barany/Controller/Index.php b/app/Barany/Controller/Index.php
new file mode 100644
index 0000000..b95e0a9
--- /dev/null
+++ b/app/Barany/Controller/Index.php
@@ -0,0 +1,71 @@
+render();
+ }
+ public function connect() {
+exit;
+ $request = Request::post(
+ $this->getAppConfig()->getPlaidApiEndpoint() . 'connect',
+ array_merge(
+ $this->getAppConfig()->getPlaidApiCredentials(),
+ array(
+ 'credentials' =>array(
+// 'username' => 'plaid_test',
+// 'password' => 'plaid_good',
+ ),
+// 'email' => 'email-test@plaid.com',
+ 'type' => 'citi',
+ 'options' => array(
+ 'login' => true,
+ ),
+ )
+ ),
+ 'application/json'
+ )
+ ->expects('application/json');
+
+
+ $response = $request->send();
+
+
+ echo '
';
+ var_dump($request->serialized_payload);
+ print_r($response->headers);
+ print_r($response->body);
+ print_r($response);
+ echo ' ';
+ }
+
+ public function connectStep() {
+exit;
+ $request = Request::post(
+ $this->getAppConfig()->getPlaidApiEndpoint() . 'connect/step',
+ array_merge(
+ $this->getAppConfig()->getPlaidApiCredentials(),
+ array(
+ 'access_token' => '',
+ 'mfa' => '',
+ )
+ ),
+ 'application/json'
+ )
+ ->expects('application/json');
+
+
+ $response = $request->send();
+
+
+ echo '';
+ var_dump($request->serialized_payload);
+ print_r($response->headers);
+ print_r($response->body);
+ print_r($response);
+ echo ' ';
+ }
+}
\ No newline at end of file
diff --git a/app/Barany/Core/AppConfig.php b/app/Barany/Core/AppConfig.php
new file mode 100644
index 0000000..bd34eb5
--- /dev/null
+++ b/app/Barany/Core/AppConfig.php
@@ -0,0 +1,16 @@
+ $this->getPlaidApiClientId(),
+ 'secret' => $this->getPlaidApiSecret(),
+ );
+ }
+}
\ No newline at end of file
diff --git a/app/Barany/Core/AppController.php b/app/Barany/Core/AppController.php
new file mode 100644
index 0000000..23326ba
--- /dev/null
+++ b/app/Barany/Core/AppController.php
@@ -0,0 +1,51 @@
+kernel = $kernel;
+ $this->view = new View($view);
+ }
+
+ protected function getAppConfig() {
+ return $this->kernel->getAppConfig();
+ }
+
+ protected function getEntityManager() {
+ return $this->kernel->getEntityManager();
+ }
+
+ protected function render() {
+ $this->view->render();
+ }
+
+ /**
+ * @param mixed $data
+ */
+ protected function renderJson($data = null) {
+ header('Content-Type: application/json');
+ if (null === $data) {
+ return;
+ }
+ if (!is_array($data) && !$data instanceof Collection) {
+ echo json_encode($data);
+ return;
+ }
+ $exportedData = [];
+ foreach ($data as $k => $v) {
+ $exportedData[$k] = $v instanceof Exportable ? $v->toApi() : $v;
+ }
+ echo json_encode($exportedData);
+ }
+}
\ No newline at end of file
diff --git a/app/Barany/Core/Http/Kernel.php b/app/Barany/Core/Http/Kernel.php
new file mode 100644
index 0000000..414203b
--- /dev/null
+++ b/app/Barany/Core/Http/Kernel.php
@@ -0,0 +1,53 @@
+appConfig = $appConfig;
+ $this->router = new Router($this);
+ $this->setupDoctrine();
+ }
+
+ private function setupDoctrine() {
+ $paths = array(ROOT . '/app/Barany/Model');
+//@todo: Set via config
+$isDevMode = true;
+
+ $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
+ $config->setNamingStrategy(new UnderscoreNamingStrategy());
+ $this->entityManager = EntityManager::create($this->appConfig->getDatabaseCredentials(), $config);
+ }
+
+ public function execute() {
+ $this->router->dispatch();
+ }
+
+ public function getAppConfig() {
+ return $this->appConfig;
+ }
+
+ public function getEntityManager() {
+ return $this->entityManager;
+ }
+}
diff --git a/app/Barany/Core/Http/Router.php b/app/Barany/Core/Http/Router.php
new file mode 100644
index 0000000..589d56a
--- /dev/null
+++ b/app/Barany/Core/Http/Router.php
@@ -0,0 +1,47 @@
+kernel = $kernel;
+ $this->klein = new Klein();
+ $this->load();
+ }
+
+ public function dispatch() {
+ $this->klein->dispatch();
+ }
+
+ /**
+ * @todo: don't eagerly create a new object for each route
+ */
+ private function load() {
+ $this->klein->get('/', $this->toCallable('Index', 'index'));
+// $this->klein->get('/connect', $this->toCallable('Index', 'connect'));
+// $this->klein->get('/connect/step', $this->toCallable('Index', 'connectStep'));
+
+ $this->klein->get('/api/institutions', $this->toCallable('Api', 'institutions'));
+ $this->klein->get('/api/accounts', $this->toCallable('Api', 'accounts'));
+ $this->klein->get('/api/account/[:account_id]', $this->toCallable('Api', 'account'));
+ }
+
+ private function toCallable($controller, $action) {
+ $class = '\Barany\Controller\\' . $controller;
+ /** @var AppController $controllerObject */
+ $controllerObject = new $class($this->kernel, $controller . '/' . $action);
+ return array($controllerObject, $action);
+ }
+}
\ No newline at end of file
diff --git a/app/Barany/Core/View.php b/app/Barany/Core/View.php
new file mode 100644
index 0000000..c7cf9f3
--- /dev/null
+++ b/app/Barany/Core/View.php
@@ -0,0 +1,30 @@
+view = $view;
+ }
+
+ public function setLayout($layout) {
+ $this->layout = $layout;
+ }
+
+ public function setView($view) {
+ $this->view = $view;
+ }
+
+ public function render() {
+ if ($this->view === null) {
+ throw new \RuntimeException('View is null!');
+ }
+
+ $layout = file_get_contents(ROOT . '/view/layouts/' . $this->layout . '.html');
+ $view = file_get_contents(ROOT . '/view/views/' . $this->view . '.html');
+
+ echo str_replace('{{body}}', $view, $layout);
+ }
+}
\ No newline at end of file
diff --git a/app/Barany/Model/Account.php b/app/Barany/Model/Account.php
new file mode 100644
index 0000000..e3c8cd3
--- /dev/null
+++ b/app/Barany/Model/Account.php
@@ -0,0 +1,64 @@
+id;
+ }
+
+ /**
+ * @return Institution
+ */
+ public function getInstitution() {
+ return $this->institution;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessToken() {
+ return $this->accessToken;
+ }
+
+ /**
+ * @return array
+ */
+ public function toApi()
+ {
+ return [
+ 'id' => $this->getId(),
+ 'name' => $this->getInstitution()->getName(),
+ 'code' => $this->getInstitution()->getCode(),
+ ];
+ }
+}
\ No newline at end of file
diff --git a/app/Barany/Model/Exportable.php b/app/Barany/Model/Exportable.php
new file mode 100644
index 0000000..cef326a
--- /dev/null
+++ b/app/Barany/Model/Exportable.php
@@ -0,0 +1,6 @@
+id;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCode() {
+ return $this->code;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * @return array
+ */
+ public function toApi() {
+ return [
+ 'id' => $this->getId(),
+ 'name' => $this->getName(),
+ 'code' => $this->getCode(),
+ ];
+ }
+}
\ No newline at end of file
diff --git a/app/Barany/Model/User.php b/app/Barany/Model/User.php
new file mode 100644
index 0000000..715da55
--- /dev/null
+++ b/app/Barany/Model/User.php
@@ -0,0 +1,48 @@
+accounts = new ArrayCollection();
+ }
+
+ /**
+ * @return ArrayCollection
+ */
+ public function getAccounts() {
+ return $this->accounts;
+ }
+
+ /**
+ * @return array
+ */
+ public function toApi()
+ {
+ return [
+ 'id' => $this->id,
+ ];
+ }
+}
\ No newline at end of file
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..84d7855
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,14 @@
+{
+ "name": "Plaid-Backend",
+ "version": "0.0.1",
+ "authors": [
+ "Michael Barany "
+ ],
+ "main": "webroot/_/css/main.css",
+ "license": "Apache2",
+ "private": true,
+ "dependencies": {
+ "angular": "~1.2.16",
+ "angular-route": "~1.2.16"
+ }
+}
\ No newline at end of file
diff --git a/cli-config.php b/cli-config.php
new file mode 100644
index 0000000..b057208
--- /dev/null
+++ b/cli-config.php
@@ -0,0 +1,8 @@
+getEntityManager());
diff --git a/cli/console.php b/cli/console.php
new file mode 100644
index 0000000..e2ab5ca
--- /dev/null
+++ b/cli/console.php
@@ -0,0 +1,5 @@
+=5.3.2"
+ },
+ "require-dev": {
+ "doctrine/cache": "1.*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\Common\\Annotations\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com",
+ "homepage": "http://www.jwage.com/",
+ "role": "Creator"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com",
+ "homepage": "http://www.instaclick.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com",
+ "homepage": "http://jmsyst.com",
+ "role": "Developer of wrapped JMSSerializerBundle"
+ }
+ ],
+ "description": "Docblock Annotations Parser",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "annotations",
+ "docblock",
+ "parser"
+ ],
+ "time": "2013-06-16 21:33:03"
+ },
+ {
+ "name": "doctrine/cache",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/cache.git",
+ "reference": "e16d7adf45664a50fa86f515b6d5e7f670130449"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/cache/zipball/e16d7adf45664a50fa86f515b6d5e7f670130449",
+ "reference": "e16d7adf45664a50fa86f515b6d5e7f670130449",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "conflict": {
+ "doctrine/common": ">2.2,<2.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": ">=3.7",
+ "satooshi/php-coveralls": "~0.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\Common\\Cache\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jonathan H. Wage",
+ "email": "jonwage@gmail.com",
+ "homepage": "http://www.jwage.com/",
+ "role": "Creator"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com",
+ "homepage": "http://www.instaclick.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com",
+ "homepage": "http://jmsyst.com",
+ "role": "Developer of wrapped JMSSerializerBundle"
+ }
+ ],
+ "description": "Caching library offering an object-oriented API for many cache backends",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "cache",
+ "caching"
+ ],
+ "time": "2013-10-25 19:04:14"
+ },
+ {
+ "name": "doctrine/collections",
+ "version": "v1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/collections.git",
+ "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
+ "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\Common\\Collections\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com",
+ "homepage": "http://www.jwage.com/",
+ "role": "Creator"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com",
+ "homepage": "http://www.instaclick.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com",
+ "homepage": "http://jmsyst.com",
+ "role": "Developer of wrapped JMSSerializerBundle"
+ }
+ ],
+ "description": "Collections Abstraction library",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "array",
+ "collections",
+ "iterator"
+ ],
+ "time": "2014-02-03 23:07:43"
+ },
+ {
+ "name": "doctrine/common",
+ "version": "v2.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/common.git",
+ "reference": "ceb18cf9b0230f3ea208b6238130fd415abda0a7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/common/zipball/ceb18cf9b0230f3ea208b6238130fd415abda0a7",
+ "reference": "ceb18cf9b0230f3ea208b6238130fd415abda0a7",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/annotations": "1.*",
+ "doctrine/cache": "1.*",
+ "doctrine/collections": "1.*",
+ "doctrine/inflector": "1.*",
+ "doctrine/lexer": "1.*",
+ "php": ">=5.3.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.4.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\Common\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com",
+ "homepage": "http://www.jwage.com/",
+ "role": "Creator"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com",
+ "homepage": "http://www.instaclick.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com",
+ "homepage": "http://jmsyst.com",
+ "role": "Developer of wrapped JMSSerializerBundle"
+ }
+ ],
+ "description": "Common Library for Doctrine projects",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "annotations",
+ "collections",
+ "eventmanager",
+ "persistence",
+ "spl"
+ ],
+ "time": "2013-09-07 10:20:34"
+ },
+ {
+ "name": "doctrine/dbal",
+ "version": "v2.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/dbal.git",
+ "reference": "fec965d330c958e175c39e61c3f6751955af32d0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/dbal/zipball/fec965d330c958e175c39e61c3f6751955af32d0",
+ "reference": "fec965d330c958e175c39e61c3f6751955af32d0",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/common": "~2.4",
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*",
+ "symfony/console": "~2.0"
+ },
+ "suggest": {
+ "symfony/console": "Allows use of the command line interface"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\DBAL\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com",
+ "homepage": "http://www.jwage.com/",
+ "role": "Creator"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com",
+ "homepage": "http://www.instaclick.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ }
+ ],
+ "description": "Database Abstraction Layer",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "database",
+ "dbal",
+ "persistence",
+ "queryobject"
+ ],
+ "time": "2014-01-01 16:43:57"
+ },
+ {
+ "name": "doctrine/inflector",
+ "version": "v1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/inflector.git",
+ "reference": "54b8333d2a5682afdc690060c1cf384ba9f47f08"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/inflector/zipball/54b8333d2a5682afdc690060c1cf384ba9f47f08",
+ "reference": "54b8333d2a5682afdc690060c1cf384ba9f47f08",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\Common\\Inflector\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com",
+ "homepage": "http://www.jwage.com/",
+ "role": "Creator"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com",
+ "homepage": "http://www.instaclick.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com",
+ "homepage": "http://jmsyst.com",
+ "role": "Developer of wrapped JMSSerializerBundle"
+ }
+ ],
+ "description": "Common String Manipulations with regard to casing and singular/plural rules.",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "inflection",
+ "pluarlize",
+ "singuarlize",
+ "string"
+ ],
+ "time": "2013-01-10 21:49:15"
+ },
+ {
+ "name": "doctrine/lexer",
+ "version": "v1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/lexer.git",
+ "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/lexer/zipball/2f708a85bb3aab5d99dab8be435abd73e0b18acb",
+ "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\Common\\Lexer\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com",
+ "homepage": "http://www.instaclick.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Johannes Schmitt",
+ "email": "schmittjoh@gmail.com",
+ "homepage": "http://jmsyst.com",
+ "role": "Developer of wrapped JMSSerializerBundle"
+ }
+ ],
+ "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "lexer",
+ "parser"
+ ],
+ "time": "2013-01-12 18:59:04"
+ },
+ {
+ "name": "doctrine/orm",
+ "version": "v2.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/doctrine2.git",
+ "reference": "0363a5548d9263f979f9ca149decb9cfc66419ab"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/0363a5548d9263f979f9ca149decb9cfc66419ab",
+ "reference": "0363a5548d9263f979f9ca149decb9cfc66419ab",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/collections": "~1.1",
+ "doctrine/dbal": "~2.4",
+ "ext-pdo": "*",
+ "php": ">=5.3.2",
+ "symfony/console": "~2.0"
+ },
+ "require-dev": {
+ "satooshi/php-coveralls": "dev-master",
+ "symfony/yaml": "~2.1"
+ },
+ "suggest": {
+ "symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
+ },
+ "bin": [
+ "bin/doctrine",
+ "bin/doctrine.php"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.4.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Doctrine\\ORM\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com",
+ "homepage": "http://www.jwage.com/",
+ "role": "Creator"
+ },
+ {
+ "name": "Guilherme Blanco",
+ "email": "guilhermeblanco@gmail.com",
+ "homepage": "http://www.instaclick.com"
+ },
+ {
+ "name": "Roman Borschel",
+ "email": "roman@code-factory.org"
+ },
+ {
+ "name": "Benjamin Eberlei",
+ "email": "kontakt@beberlei.de"
+ }
+ ],
+ "description": "Object-Relational-Mapper for PHP",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "database",
+ "orm"
+ ],
+ "time": "2014-02-08 16:35:09"
+ },
+ {
+ "name": "klein/klein",
+ "version": "v2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/chriso/klein.php.git",
+ "reference": "6e1f228ce82333b437402dafad049713eb3eeac6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/chriso/klein.php/zipball/6e1f228ce82333b437402dafad049713eb3eeac6",
+ "reference": "6e1f228ce82333b437402dafad049713eb3eeac6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.x"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Klein": "."
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Chris O'Hara",
+ "email": "cohara87@gmail.com",
+ "homepage": "http://chris6f.com/",
+ "role": "Creator/Developer"
+ },
+ {
+ "name": "Trevor Suarez",
+ "email": "rican7@gmail.com",
+ "homepage": "http://about.me/tnsuarez",
+ "role": "Contributor/Developer"
+ }
+ ],
+ "description": "A lightning fast router for PHP",
+ "homepage": "https://github.com/chriso/klein.php",
+ "keywords": [
+ "boilerplate",
+ "router",
+ "routing",
+ "sinatra"
+ ],
+ "time": "2013-06-16 23:32:47"
+ },
+ {
+ "name": "nategood/httpful",
+ "version": "0.2.11",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nategood/httpful.git",
+ "reference": "0bf1423028abe2f630e1d2ef8d62486d6655b2f3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nategood/httpful/zipball/0bf1423028abe2f630e1d2ef8d62486d6655b2f3",
+ "reference": "0bf1423028abe2f630e1d2ef8d62486d6655b2f3",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "php": ">=5.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Httpful": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nate Good",
+ "email": "me@nategood.com",
+ "homepage": "http://nategood.com"
+ }
+ ],
+ "description": "A Readable, Chainable, REST friendly, PHP HTTP Client",
+ "homepage": "http://github.com/nategood/httpful",
+ "keywords": [
+ "api",
+ "curl",
+ "http",
+ "requests",
+ "rest",
+ "restful"
+ ],
+ "time": "2013-10-20 11:03:40"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v2.4.4",
+ "target-dir": "Symfony/Component/Console",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Console.git",
+ "reference": "2e452005b1e1d003d23702d227e23614679eb5ca"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Console/zipball/2e452005b1e1d003d23702d227e23614679eb5ca",
+ "reference": "2e452005b1e1d003d23702d227e23614679eb5ca",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "symfony/event-dispatcher": "~2.1"
+ },
+ "suggest": {
+ "symfony/event-dispatcher": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Console\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com",
+ "homepage": "http://fabien.potencier.org",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Console Component",
+ "homepage": "http://symfony.com",
+ "time": "2014-04-27 13:34:57"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "platform": [],
+ "platform-dev": []
+}
diff --git a/config/Config.php.sample b/config/Config.php.sample
new file mode 100644
index 0000000..75e0591
--- /dev/null
+++ b/config/Config.php.sample
@@ -0,0 +1,26 @@
+ 'pdo_mysql',
+ 'user' => 'user',
+ 'password' => 'password',
+ 'dbname' => 'plaid_database',
+ ];
+ }
+}
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000..3dc2d82
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,15 @@
+var gulp = require('gulp');
+var clean = require('gulp-clean');
+var concat = require('gulp-concat');
+var gulpBowerFiles = require('gulp-bower-files');
+
+gulp.task('clean', function () {
+ return gulp.src('webroot/_/build', {read: false})
+ .pipe(clean());
+});
+
+gulp.task("bower-files", function(){
+ gulpBowerFiles()
+ .pipe(concat('vendor.js'))
+ .pipe(gulp.dest("webroot/_/build"));
+});
diff --git a/include.php b/include.php
new file mode 100644
index 0000000..e01eeae
--- /dev/null
+++ b/include.php
@@ -0,0 +1,26 @@
+",
+ "license": "Apache2"
+}
diff --git a/view/layouts/default.html b/view/layouts/default.html
new file mode 100644
index 0000000..7c01968
--- /dev/null
+++ b/view/layouts/default.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+{{body}}
+
+
diff --git a/view/views/Index/index.html b/view/views/Index/index.html
new file mode 100644
index 0000000..223598a
--- /dev/null
+++ b/view/views/Index/index.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
Add More
+
+
+ {{account.name}} (Add)
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/webroot/.htaccess b/webroot/.htaccess
new file mode 100644
index 0000000..fc833c8
--- /dev/null
+++ b/webroot/.htaccess
@@ -0,0 +1,3 @@
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule . /index.php [L]
diff --git a/webroot/_/css/main.css b/webroot/_/css/main.css
new file mode 100644
index 0000000..c0465dd
--- /dev/null
+++ b/webroot/_/css/main.css
@@ -0,0 +1,3 @@
+html {
+ padding: 10px;
+}
\ No newline at end of file
diff --git a/webroot/_/js/controllers.js b/webroot/_/js/controllers.js
new file mode 100644
index 0000000..c6698dd
--- /dev/null
+++ b/webroot/_/js/controllers.js
@@ -0,0 +1,75 @@
+var cache = {
+ accounts: {}
+};
+
+angular.module('myApp', ['ngRoute'])
+
+ .controller('MainController', function($scope, $route, $routeParams, $location) {
+ $scope.$route = $route;
+ $scope.$location = $location;
+ $scope.$routeParams = $routeParams;
+ })
+
+ .controller('ListAccountController', function($scope, $http) {
+ $scope.accounts = [];
+ $http.get("/api/accounts")
+ .success(function(data) {
+ $scope.accounts = data;
+ })
+ .error(function() {
+ console.log("Error!!!!");
+ });
+ })
+
+ .controller('ListInstitutionController', function($scope, $http) {
+ $scope.accounts = [];
+ $http.get("/api/institutions")
+ .success(function(data) {
+ $scope.accounts = data;
+ })
+ .error(function() {
+ console.log("Error!!!!");
+ });
+ })
+
+ .controller('ViewAccountController', function($scope, $routeParams, $http) {
+ if (cache.accounts[$routeParams.accountId]) {
+ $scope.data = cache.accounts[$routeParams.accountId];
+ return;
+ }
+ $scope.data = [];
+ $http.get("/api/account/" + $routeParams.accountId)
+ .success(function(data) {
+ for (var i in data.accounts) {
+ var balance = data.accounts[i].account.balance.current;
+ for (var j in data.accounts[i].transactions) {
+ data.accounts[i].transactions[j].balance = balance;
+ balance = balance + data.accounts[i].transactions[j].amount;
+ }
+ }
+ cache.accounts[$routeParams.accountId] = data;
+ $scope.data = data;
+ console.log(data);
+ })
+ .error(function() {
+ console.log("Error!!!!");
+ });
+ })
+
+ .controller('AddAccountController', function($scope, $routeParams) {
+ $scope.name = "AddAccountController";
+ $scope.params = $routeParams;
+ })
+
+ .config(function($routeProvider, $locationProvider) {
+ $locationProvider.hashPrefix('!');
+ $routeProvider
+ .when('/account/:accountId', {
+ templateUrl: '/_/views/view-account.html',
+ controller: 'ViewAccountController'
+ })
+ .when('/add/:accountId', {
+ templateUrl: '/_/views/add-account.html',
+ controller: 'AddAccountController'
+ });
+ });
diff --git a/webroot/_/views/add-account.html b/webroot/_/views/add-account.html
new file mode 100644
index 0000000..3235153
--- /dev/null
+++ b/webroot/_/views/add-account.html
@@ -0,0 +1,5 @@
+Add Account
+
\ No newline at end of file
diff --git a/webroot/_/views/view-account.html b/webroot/_/views/view-account.html
new file mode 100644
index 0000000..8fb2141
--- /dev/null
+++ b/webroot/_/views/view-account.html
@@ -0,0 +1,32 @@
+
+
+
{{data.institution.name}}
+
+
+
+
{{account.account.meta.name}} ({{account.account.meta.number}})
+
Available: {{account.account.balance.available | currency : $}}
+
Current: {{account.account.balance.current | currency : $}}
+
+
+
+
+ Date
+ Description
+ Amount
+ Balance
+
+
+
+
+ {{transaction.date | date}}
+ {{transaction.name}}
+ {{transaction.amount * -1 | currency : $}}
+ {{transaction.balance | currency : $}}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/webroot/index.php b/webroot/index.php
new file mode 100644
index 0000000..fc09dcc
--- /dev/null
+++ b/webroot/index.php
@@ -0,0 +1,7 @@
+execute();