diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index a2ea0d90..80a61cb9 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -1,13 +1,23 @@ -import React from 'react'; -import {Router, Route, IndexRoute, browserHistory} from 'react-router'; +const React = require('react'); +const {Router, Route, IndexRoute, browserHistory} = require('react-router'); -import App from 'app/App'; -import DemoPage from 'app/demo/components-demo-page'; +const App = require('app/App'); +const DemoPage = require('app/demo/components-demo-page'); -import MainLayout from 'app/main/main-layout'; -import MainHomePage from 'app/main/main-home/main-home-page'; -import MainSignUpPage from 'app/main/main-signup/main-signup-page'; +const MainLayout = require('app/main/main-layout'); +const MainHomePage = require('app/main/main-home/main-home-page'); +const MainSignUpPage = require('app/main/main-signup/main-signup-page'); +const DashboardLayout = require('app/main/dashboard/dashboard-layout'); + +const DashboardListTicketsPage = require('app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page'); +const DashboardListArticlesPage = require('app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page'); + +const DashboardCreateTicketPage = require('app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page'); +const DashboardEditProfilePage = require('app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page'); + +const DashboardArticlePage = require('app/main/dashboard/dashboard-article/dashboard-article-page'); +const DashboardTicketPage = require('app/main/dashboard/dashboard-ticket/dashboard-ticket-page'); export default ( <Router history={browserHistory}> @@ -15,6 +25,16 @@ export default ( <Route path='/app' component={MainLayout}> <IndexRoute component={MainHomePage} /> <Route path='signup' component={MainSignUpPage}/> + <Route path='dashboard' component={DashboardLayout}> + <IndexRoute component={DashboardListTicketsPage} /> + <Route path='articles' component={DashboardListArticlesPage}/> + + <Route path='create-ticket' component={DashboardCreateTicketPage}/> + <Route path='edit-profile' component={DashboardEditProfilePage}/> + + <Route path='article' component={DashboardArticlePage}/> + <Route path='ticket' component={DashboardTicketPage}/> + </Route> </Route> <Route name='Demo' path='demo' component={DemoPage} /> diff --git a/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js b/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js new file mode 100644 index 00000000..cdfbf4d2 --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-article/dashboard-article-page.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const DashboardArticlePage = React.createClass({ + + render() { + return ( + <div> + DASHBOARD ARTICLE + </div> + ); + } +}); + +export default DashboardArticlePage; diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js new file mode 100644 index 00000000..aff1aaa2 --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-create-ticket/dashboard-create-ticket-page.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const DashboardCreateTicketPage = React.createClass({ + + render() { + return ( + <div> + DASHBOARD CREATE TICKET + </div> + ); + } +}); + +export default DashboardCreateTicketPage; diff --git a/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js b/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js new file mode 100644 index 00000000..9073edb0 --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const DashboardEditProfilePage = React.createClass({ + + render() { + return ( + <div> + DASHBOARD EDIT PROFILE + </div> + ); + } +}); + +export default DashboardEditProfilePage; diff --git a/client/src/app/main/dashboard/dashboard-layout.js b/client/src/app/main/dashboard/dashboard-layout.js new file mode 100644 index 00000000..29f3fc69 --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-layout.js @@ -0,0 +1,16 @@ +import React from 'react'; +import DashboardMenu from 'app/main/dashboard/dashboard-menu'; + +const DashboardLayout = React.createClass({ + + render() { + return ( + <div> + <div><DashboardMenu location={this.props.location} /></div> + <div>{this.props.children}</div> + </div> + ); + } +}); + +export default DashboardLayout; diff --git a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js new file mode 100644 index 00000000..1488cd58 --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const DashboardListArticlesPage = React.createClass({ + + render() { + return ( + <div> + DASHBOARD ARTICLES LIST + </div> + ); + } +}); + +export default DashboardListArticlesPage; diff --git a/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.js b/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.js new file mode 100644 index 00000000..e3b9201e --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const DashboardListTicketsPage = React.createClass({ + + render() { + return ( + <div> + DASHBOARD TICKET LIST + </div> + ); + } +}); + +export default DashboardListTicketsPage; diff --git a/client/src/app/main/dashboard/dashboard-menu.js b/client/src/app/main/dashboard/dashboard-menu.js new file mode 100644 index 00000000..2f64001b --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-menu.js @@ -0,0 +1,57 @@ +import React from 'react'; +import _ from 'lodash'; + +import Menu from 'core-components/menu'; + +let dashboardRoutes = [ + { path: '/app/dashboard', text: 'Ticket List' }, + { path: '/app/dashboard/create-ticket', text: 'Create Ticket' }, + { path: '/app/dashboard/articles', text: 'View Articles' }, + { path: '/app/dashboard/edit-profile', text: 'Edit Profile' } +]; + +const DashboardMenu = React.createClass({ + contextTypes: { + router: React.PropTypes.object + }, + + propTypes: { + location: React.PropTypes.object + }, + + render() { + return ( + <Menu {...this.getProps()} /> + ); + }, + + getProps() { + return { + items: this.getMenuItems(), + selectedIndex: this.getSelectedIndex(), + onItemClick: this.goToPathByIndex + }; + }, + + getMenuItems: function () { + return dashboardRoutes.map(this.getMenuItem); + }, + + getMenuItem(item) { + return { + content: item.text + }; + }, + + getSelectedIndex() { + let pathname = this.props.location.pathname; + + return _.findIndex(dashboardRoutes, {path: pathname}); + }, + + goToPathByIndex(itemIndex) { + this.context.router.push(dashboardRoutes[itemIndex].path); + } +}); + +export default DashboardMenu; diff --git a/client/src/app/main/dashboard/dashboard-ticket/dashboard-ticket-page.js b/client/src/app/main/dashboard/dashboard-ticket/dashboard-ticket-page.js new file mode 100644 index 00000000..f0c30458 --- /dev/null +++ b/client/src/app/main/dashboard/dashboard-ticket/dashboard-ticket-page.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const DashboardTicketPage = React.createClass({ + + render() { + return ( + <div> + DASHBOARD TICKET PAGE + </div> + ); + } +}); + +export default DashboardTicketPage; diff --git a/client/src/core-components/icon.js b/client/src/core-components/icon.js index 26c0898e..8d6770f5 100644 --- a/client/src/core-components/icon.js +++ b/client/src/core-components/icon.js @@ -26,7 +26,7 @@ const Icon = React.createClass({ renderFlag() { return ( - <img className={this.props.className} src={`../images/icons/${this.props.name}.png`} aria-hidden="true" /> + <img className={this.props.className} src={`/images/icons/${this.props.name}.png`} aria-hidden="true" /> ); }, diff --git a/client/src/core-components/menu.scss b/client/src/core-components/menu.scss index e872f7b1..a0beb93f 100644 --- a/client/src/core-components/menu.scss +++ b/client/src/core-components/menu.scss @@ -11,6 +11,7 @@ &__list-item { padding: 8px; + &_selected, &:hover { background-color: $primary-red; color: white; @@ -23,6 +24,7 @@ } &_secondary { + .menu__list-item_selected, .menu__list-item:hover { background-color: $secondary-blue; } diff --git a/server/composer.json b/server/composer.json index b64cad11..fc910636 100644 --- a/server/composer.json +++ b/server/composer.json @@ -2,6 +2,7 @@ "require": { "slim/slim": "~2.0", "gabordemooij/redbean": "~4.2", + "respect/validation": "^1.1", "phpmailer/phpmailer": "^5.2" }, "require-dev": { diff --git a/server/controllers/ticket.php b/server/controllers/ticket.php index 95ab2dda..eaab3316 100644 --- a/server/controllers/ticket.php +++ b/server/controllers/ticket.php @@ -1,9 +1,11 @@ <?php include 'ticket/create.php'; +include 'ticket/comment.php'; $ticketControllers = new ControllerGroup(); $ticketControllers->setGroupPath('/ticket'); $ticketControllers->addController(new CreateController); +$ticketControllers->addController(new CommentController); $ticketControllers->finalize(); \ No newline at end of file diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php new file mode 100644 index 00000000..f1a82231 --- /dev/null +++ b/server/controllers/ticket/comment.php @@ -0,0 +1,39 @@ +<?php +use RedBeanPHP\Facade as RedBean; + +class CommentController extends Controller { + const PATH = '/comment'; + + private $ticketId; + private $content; + + public function validations() { + return [ + 'permission' => 'any', + 'requestData' => [] + ]; + } + + public function handler() { + $this->requestData(); + $this->storeComment(); + + Response::respondSuccess(); + } + + private function requestData() { + $this->ticketId = Controller::request('ticketId'); + $this->content = Controller::request('content'); + } + + private function storeComment() { + $comment = new Comment(); + $comment->setProperties(array( + 'content' => $this->content + )); + + $ticket = Ticket::getTicket($this->ticketId); + $ticket->addComment($comment); + $ticket->store(); + } +} \ No newline at end of file diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index 845b415c..1b8bd8c7 100644 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -1,51 +1,46 @@ <?php +use RedBeanPHP\Facade as RedBean; + +use Respect\Validation\Validator as DataValidator; class CreateController extends Controller { const PATH = '/create'; - private $title ; + private $title; private $content; private $departmentId; private $language; - public function handler() { - $this->requestTicketData(); - - $validateResult = $this->validateData(); - - if ($validateResult !== true) { - Response::respondError($validateResult); - } else { - $this->storeTicket(); - - Response::respondSuccess(); - } + public function validations() { + return [ + 'permission' => 'any', + 'requestData' => [ + 'title' => [ + 'validation' => DataValidator::length(3, 30), + 'error' => ERRORS::INVALID_TITLE + ], + 'content' => [ + 'validation' => DataValidator::length(10, 500), + 'error' => ERRORS::INVALID_CONTENT + ] + ] + ]; } - private function requestTicketData() { + public function handler() { + $this->storeRequestData(); + $this->storeTicket(); + + Response::respondSuccess(); + } + + private function storeRequestData() { $this->title = Controller::request('title'); $this->content = Controller::request('content'); $this->departmentId = Controller::request('departmentId'); $this->language = Controller::request('language'); } - private function validateData() { - if (strlen($this->title) < 3) { - return ERRORS::SHORT_TITLE; - } - if (strlen($this->title) > 30) { - return ERRORS::LONG_TITLE; - } - if (strlen($this->content) < 5) { - return ERRORS::SHORT_CONTENT; - } - if (strlen($this->content) > 500) { - return ERRORS::LONG_CONTENT; - } - - return true; - } - private function storeTicket() { $ticket = new Ticket(); $ticket->setProperties(array( @@ -55,13 +50,14 @@ class CreateController extends Controller { 'language' => $this->language, 'department' => $this->departmentId, 'file' => '', - 'date' => date("F j, Y, g:i a"), + 'date' => date('F j, Y, g:i a'), 'unread' => false, - 'closed' => false, - 'author' => '', - 'owner'=> '', - 'ownComments' => [] + 'closed' => false )); + + //TODO: Add logged user as author + $ticket->setAuthor(User::getUser(1)); + $ticket->store(); } } \ No newline at end of file diff --git a/server/controllers/user/login.php b/server/controllers/user/login.php index 396f5acf..54357d80 100644 --- a/server/controllers/user/login.php +++ b/server/controllers/user/login.php @@ -5,6 +5,13 @@ class LoginController extends Controller { private $userInstance; private $session; + + public function validations() { + return [ + 'permission' => 'any', + 'requestData' => [] + ]; + } public function handler() { if ($this->isAlreadyLoggedIn()) { diff --git a/server/controllers/user/logout.php b/server/controllers/user/logout.php index cab4cccd..60e51c80 100644 --- a/server/controllers/user/logout.php +++ b/server/controllers/user/logout.php @@ -2,6 +2,13 @@ class LogoutController extends Controller { const PATH = '/logout'; + public function validations() { + return [ + 'permission' => 'any', + 'requestData' => [] + ]; + } + public function handler() { $session = Session::getInstance(); $session->closeSession(); diff --git a/server/controllers/user/signup.php b/server/controllers/user/signup.php index 1b3d7dc5..947b2fb9 100644 --- a/server/controllers/user/signup.php +++ b/server/controllers/user/signup.php @@ -3,24 +3,25 @@ class SignUpController extends Controller { const PATH = '/signup'; - private $email; - private $password; + public function validations() { + return [ + 'permission' => 'any', + 'requestData' => [] + ]; + } public function handler() { - $this->requestUserData(); + $email = Controller::request('email'); + $password = Controller::request('password'); - $userId = $this->createNewUserAndRetrieveId($this->email, $this->password); + $userId = $this->createNewUserAndRetrieveId($email, $password); + + EmailSender::validRegister($email); Response::respondSuccess(array( 'userId' => $userId, - 'userEmail' => $this->email + 'userEmail' => $email )); - - EmailSender::validRegister($this->email); - } - public function requestUserData(){ - $this->email = Controller::request('email'); - $this->password = Controller::request('password'); } public function createNewUserAndRetrieveId($email, $password) { diff --git a/server/index.php b/server/index.php index 8ea3e907..5ce7a36f 100644 --- a/server/index.php +++ b/server/index.php @@ -21,13 +21,13 @@ spl_autoload_register(function ($class) { $classPath = "models/{$class}.php"; if(file_exists($classPath)) { - include $classPath; + include_once $classPath; } }); // LOAD CONTROLLERS foreach (glob('controllers/*.php') as $controller) { - include $controller; + include_once $controller; } $app->run(); diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 11770fc7..6f809351 100644 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -1,4 +1,5 @@ <?php +require_once 'libs/Validator.php'; abstract class Controller { @@ -6,40 +7,37 @@ abstract class Controller { * Instance-related stuff */ abstract public function handler(); + abstract public function validations(); public function getHandler() { return function () { + try { + $this->validate(); + } catch (ValidationException $exception) { + Response::respondError($exception->getMessage()); + return; + } + $this->handler(); }; } + + public function validate() { + $validator = new Validator(); + + $validator->validate($this->validations()); + } public static function request($key) { $app = self::getAppInstance(); return $app->request()->post($key); } - - public static function checkUserLogged() { - $session = Session::getInstance(); - - return $session->checkAuthentication(array( - 'user_id' => self::request('csrf_userid'), - 'token' => self::request('csrf_token') - )); - } - + public static function getLoggedUser() { return User::getUser((int)self::request('csrf_userid')); } - public static function checkStaffLogged() { - return self::checkUserLogged() && (self::getLoggedUser()->admin === 1); - } - - public static function checkAdminLogged() { - return self::checkUserLogged() && (self::getLoggedUser()->admin === 2); - } - public static function getAppInstance() { return \Slim\Slim::getInstance(); } diff --git a/server/libs/Validator.php b/server/libs/Validator.php new file mode 100644 index 00000000..3ab52485 --- /dev/null +++ b/server/libs/Validator.php @@ -0,0 +1,61 @@ +<?php +require_once 'libs/Controller.php'; + +use Respect\Validation\Validator as DataValidator; + +class ValidationException extends Exception {} + +class Validator { + + public function validate($config) { + $this->validatePermissions($config['permission']); + $this->validateAllRequestData($config['requestData']); + } + + private function validatePermissions($permission) { + $permissions = [ + 'any' => true, + 'user' => $this->isUserLogged(), + 'staff' => $this->isStaffLogged(), + 'admin' => $this->isAdminLogged() + ]; + + if (!$permissions[$permission]) { + throw new ValidationException(ERRORS::NO_PERMISSION); + } + } + + private function validateAllRequestData($requestDataValidations) { + foreach ($requestDataValidations as $requestDataKey => $requestDataValidationConfig) { + $requestDataValue = Controller::request($requestDataKey); + $requestDataValidator = $requestDataValidationConfig['validation']; + $requestDataValidationErrorMessage = $requestDataValidationConfig['error']; + + $this->validateData($requestDataValue, $requestDataValidator, $requestDataValidationErrorMessage); + } + } + + private function validateData($value, DataValidator $dataValidator, $error) { + if (!$dataValidator->validate($value)) { + throw new ValidationException($error); + } + } + + private function isUserLogged() { + $session = Session::getInstance(); + + return $session->checkAuthentication(array( + 'userId' => Controller::request('csrf_userid'), + 'token' => Controller::request('csrf_token') + )); + } + + private function isStaffLogged() { + return $this->isUserLogged() && (Controller::getLoggedUser()->admin === 1); + } + + private function isAdminLogged() { + return $this->isUserLogged() && (Controller::getLoggedUser()->admin === 2); + } + +} \ No newline at end of file diff --git a/server/models/Comment.php b/server/models/Comment.php index 968e013b..da011200 100644 --- a/server/models/Comment.php +++ b/server/models/Comment.php @@ -1,7 +1,7 @@ <?php class Comment extends DataStore { - const TABLE = 'comments'; + const TABLE = 'comment'; public static function getProps() { return array( diff --git a/server/models/ERRORS.php b/server/models/ERRORS.php index 76d29f3c..a8dbe39c 100644 --- a/server/models/ERRORS.php +++ b/server/models/ERRORS.php @@ -2,8 +2,7 @@ class ERRORS { const INVALID_CREDENTIALS = 'User or password is not defined'; const SESSION_EXISTS = 'User is already logged in'; - const SHORT_TITLE = 'Title is too short'; - const LONG_TITLE = 'Title is very long'; - const SHORT_CONTENT = 'Content is too short'; - const LONG_CONTENT = 'Content is very long'; + const NO_PERMISSION = 'You have no permission to access'; + const INVALID_TITLE = 'Invalid title'; + const INVALID_CONTENT = 'Invalid content'; } diff --git a/server/models/Session.php b/server/models/Session.php index 3ca9dedd..3c9d4f5e 100644 --- a/server/models/Session.php +++ b/server/models/Session.php @@ -38,8 +38,12 @@ class Session { } public function checkAuthentication($data) { - return $this->getStoredData('userId') === $data['userId'] && - $this->getStoredData('token') === $data['token']; + $userId = $this->getStoredData('userId'); + $token = $this->getStoredData('token'); + + return $userId && $token && + $userId === $data['userId'] && + $token === $data['token']; } public function isLoggedWithId($userId) { diff --git a/server/models/Ticket.php b/server/models/Ticket.php index f1bbe75a..8d1a8fe8 100644 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -1,11 +1,14 @@ <?php +use RedBeanPHP\Facade as RedBean; class Ticket extends DataStore { - const TABLE = 'tickets'; + const TABLE = 'ticket'; + + private $author; public static function getProps() { return array( - 'ticketId', + 'ticketNumber', 'title', 'content', 'language', @@ -16,11 +19,38 @@ class Ticket extends DataStore { 'closed', 'author', 'owner', - 'ownComments' + 'ownCommentList' ); } - protected function getDefaultProps() { - return array(); + public static function getTicket($value, $property = 'id') { + return parent::getDataStore($value, $property); + } + + public function getDefaultProps() { + return array( + 'owner' => null + ); + } + + public function setAuthor(User $user) { + $this->author = $user; + $this->author->addTicket($this); + + $this->setProperties(array( + 'author' => $this->author->getBeanInstance() + )); + } + + public function addComment(Comment $comment) { + $this->getBeanInstance()->ownCommentList[] = $comment->getBeanInstance(); + } + + public function store() { + parent::store(); + + if ($this->author instanceof User) { + $this->author->store(); + } } } \ No newline at end of file diff --git a/server/models/User.php b/server/models/User.php index f1cf37b3..72359bca 100644 --- a/server/models/User.php +++ b/server/models/User.php @@ -1,7 +1,8 @@ <?php +use RedBeanPHP\Facade as RedBean; class User extends DataStore { - const TABLE = 'users'; + const TABLE = 'user'; public static function authenticate($userEmail, $userPassword) { $user = User::getUser($userEmail, 'email'); @@ -14,19 +15,16 @@ class User extends DataStore { 'email', 'password', 'name', - 'verificationToken', - 'ownTickets' + 'verificationToken' ); } public function getDefaultProps() { - return array( - 'ownTickets' => [] - ); + return array(); } - public function addTicket($ticket) { - $this->ownTickets[] = $ticket; + public function addTicket(Ticket $ticket) { + $this->getBeanInstance()->sharedTicketList[] = $ticket->getBeanInstance(); } public static function getUser($value, $property = 'id') { diff --git a/tests/ticket/comment.rb b/tests/ticket/comment.rb new file mode 100644 index 00000000..3b2b12b1 --- /dev/null +++ b/tests/ticket/comment.rb @@ -0,0 +1,14 @@ +describe 'ticket/comment/' do + it 'should fail if not logged' do + + end + + describe 'on successful request' do + it 'should add comment to current ticket' do + + end + it 'should link the comment to author' do + + end + end +end \ No newline at end of file diff --git a/tests/ticket/create.rb b/tests/ticket/create.rb index 8742c287..40e66e66 100644 --- a/tests/ticket/create.rb +++ b/tests/ticket/create.rb @@ -1,11 +1,11 @@ -describe '/user/login' do +describe '/ticket/create' do it 'should fail if title is too short' do - result = request('/ticket/create',{ + result = request('/ticket/create', { title: 'GG' }) (result['status']).should.equal('fail') - (result['message']).should.equal('Title is too short') + (result['message']).should.equal('Invalid title') end @@ -15,7 +15,7 @@ describe '/user/login' do }) (result['status']).should.equal('fail') - (result['message']).should.equal('Title is very long') + (result['message']).should.equal('Invalid title') end @@ -26,7 +26,7 @@ describe '/user/login' do }) (result['status']).should.equal('fail') - (result['message']).should.equal('Content is too short') + (result['message']).should.equal('Invalid content') end it 'should fail if content is very long' do @@ -39,7 +39,7 @@ describe '/user/login' do }) (result['status']).should.equal('fail') - (result['message']).should.equal('Content is very long') + (result['message']).should.equal('Invalid content') end @@ -50,7 +50,7 @@ describe '/user/login' do }) (result['status']).should.equal('success') - ticket = $database.getRow('tickets','Winter is coming','title') + ticket = $database.getRow('ticket','Winter is coming','title') (ticket['content']).should.equal('The north remembers') end end \ No newline at end of file diff --git a/tests/user/signup.rb b/tests/user/signup.rb index 51c3885f..c22af4c5 100644 --- a/tests/user/signup.rb +++ b/tests/user/signup.rb @@ -5,7 +5,7 @@ describe '/user/signup' do 'password' => 'custom' }) - userRow = $database.getRow('users', response['data']['userId']) + userRow = $database.getRow('user', response['data']['userId']) (userRow['email']).should.equal('steve@jobs.com') end