From 039f965a2cc65c38529bebd8fcb2e4f7a811bec0 Mon Sep 17 00:00:00 2001 From: Michael Barany Date: Fri, 23 May 2014 16:43:35 -0400 Subject: [PATCH] Initial Import --- .gitignore | 3 + app/Barany/Command.php | 6 + app/Barany/Controller/Api.php | 87 ++++ app/Barany/Controller/Index.php | 71 +++ app/Barany/Core/AppConfig.php | 16 + app/Barany/Core/AppController.php | 51 +++ app/Barany/Core/Http/Kernel.php | 53 +++ app/Barany/Core/Http/Router.php | 47 ++ app/Barany/Core/View.php | 30 ++ app/Barany/Model/Account.php | 64 +++ app/Barany/Model/Exportable.php | 6 + app/Barany/Model/Institution.php | 59 +++ app/Barany/Model/User.php | 48 ++ bower.json | 14 + cli-config.php | 8 + cli/console.php | 5 + cli/cron.php | 5 + composer.json | 7 + composer.lock | 721 ++++++++++++++++++++++++++++++ config/Config.php.sample | 26 ++ gulpfile.js | 15 + include.php | 26 ++ package.json | 18 + view/layouts/default.html | 16 + view/views/Index/index.html | 25 ++ webroot/.htaccess | 3 + webroot/_/css/main.css | 3 + webroot/_/js/controllers.js | 75 ++++ webroot/_/views/add-account.html | 5 + webroot/_/views/view-account.html | 32 ++ webroot/index.php | 7 + 31 files changed, 1552 insertions(+) create mode 100644 .gitignore create mode 100644 app/Barany/Command.php create mode 100644 app/Barany/Controller/Api.php create mode 100644 app/Barany/Controller/Index.php create mode 100644 app/Barany/Core/AppConfig.php create mode 100644 app/Barany/Core/AppController.php create mode 100644 app/Barany/Core/Http/Kernel.php create mode 100644 app/Barany/Core/Http/Router.php create mode 100644 app/Barany/Core/View.php create mode 100644 app/Barany/Model/Account.php create mode 100644 app/Barany/Model/Exportable.php create mode 100644 app/Barany/Model/Institution.php create mode 100644 app/Barany/Model/User.php create mode 100644 bower.json create mode 100644 cli-config.php create mode 100644 cli/console.php create mode 100644 cli/cron.php create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 config/Config.php.sample create mode 100644 gulpfile.js create mode 100644 include.php create mode 100644 package.json create mode 100644 view/layouts/default.html create mode 100644 view/views/Index/index.html create mode 100644 webroot/.htaccess create mode 100644 webroot/_/css/main.css create mode 100644 webroot/_/js/controllers.js create mode 100644 webroot/_/views/add-account.html create mode 100644 webroot/_/views/view-account.html create mode 100644 webroot/index.php 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 @@ +
+
+ +
+

My Accounts

+ +
+ +
+

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 : $}}

+ + + + + + + + + + + + + + + + + + +
DateDescriptionAmountBalance
{{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();