JWT complete

This commit is contained in:
mcmac 2018-02-16 15:02:03 +00:00
parent 976488dbe1
commit 56f8d8dd6a
31 changed files with 954 additions and 102 deletions

1
.idea/vereto-api.iml generated
View file

@ -67,7 +67,6 @@
<orderEntry type="library" scope="PROVIDED" name="spring-watcher-listen (v2.0.1, rbenv: 2.5.0) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="sprockets (v3.7.1, rbenv: 2.5.0) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="sprockets-rails (v3.2.1, rbenv: 2.5.0) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="sqlite3 (v1.3.13, rbenv: 2.5.0) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="thor (v0.20.0, rbenv: 2.5.0) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="thread_safe (v0.3.6, rbenv: 2.5.0) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="tzinfo (v1.2.5, rbenv: 2.5.0) [gem]" level="application" />

332
.idea/workspace.xml generated
View file

@ -2,14 +2,36 @@
<project version="4">
<component name="ChangeListManager">
<list default="true" id="42443dfa-4405-4cad-b0d1-6c57eb86e644" name="Default" comment="">
<change beforePath="" afterPath="$PROJECT_DIR$/app/controllers/concerns/response.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/support/request_spec_helper.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/app/auth/authenticate_user.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/app/auth/authorize_api_request.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/app/controllers/authentication_controller.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/app/controllers/users_controller.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/app/lib/json_web_token.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/app/lib/message.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/app/models/user.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/db/migrate/20180216131546_create_users.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/auth/authenticate_user_spec.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/auth/authorize_api_request_spec.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/controllers/application_controller_spec.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/controllers/authentication_controller_spec.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/controllers/users_controller_spec.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/factories/users.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/models/user_spec.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/requests/authentication_spec.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/requests/users_spec.rb" />
<change beforePath="" afterPath="$PROJECT_DIR$/spec/support/controller_spec_helper.rb" />
<change beforePath="$PROJECT_DIR$/.idea/vereto-api.iml" afterPath="$PROJECT_DIR$/.idea/vereto-api.iml" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
<change beforePath="$PROJECT_DIR$/Gemfile" afterPath="$PROJECT_DIR$/Gemfile" />
<change beforePath="$PROJECT_DIR$/Gemfile.lock" afterPath="$PROJECT_DIR$/Gemfile.lock" />
<change beforePath="$PROJECT_DIR$/app/controllers/application_controller.rb" afterPath="$PROJECT_DIR$/app/controllers/application_controller.rb" />
<change beforePath="$PROJECT_DIR$/app/controllers/concerns/.keep" afterPath="$PROJECT_DIR$/app/controllers/concerns/exception_handler.rb" />
<change beforePath="$PROJECT_DIR$/app/controllers/concerns/exception_handler.rb" afterPath="$PROJECT_DIR$/app/controllers/concerns/exception_handler.rb" />
<change beforePath="$PROJECT_DIR$/app/controllers/items_controller.rb" afterPath="$PROJECT_DIR$/app/controllers/items_controller.rb" />
<change beforePath="$PROJECT_DIR$/app/controllers/todos_controller.rb" afterPath="$PROJECT_DIR$/app/controllers/todos_controller.rb" />
<change beforePath="$PROJECT_DIR$/config/routes.rb" afterPath="$PROJECT_DIR$/config/routes.rb" />
<change beforePath="$PROJECT_DIR$/db/schema.rb" afterPath="$PROJECT_DIR$/db/schema.rb" />
<change beforePath="$PROJECT_DIR$/spec/rails_helper.rb" afterPath="$PROJECT_DIR$/spec/rails_helper.rb" />
<change beforePath="$PROJECT_DIR$/spec/requests/items_spec.rb" afterPath="$PROJECT_DIR$/spec/requests/items_spec.rb" />
<change beforePath="$PROJECT_DIR$/spec/requests/todos_spec.rb" afterPath="$PROJECT_DIR$/spec/requests/todos_spec.rb" />
</list>
<ignored path="$PROJECT_DIR$/.bundle/" />
@ -30,8 +52,8 @@
<file leaf-file-name="routes.rb" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/config/routes.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="54">
<caret line="3" column="20" lean-forward="false" selection-start-line="3" selection-start-column="20" selection-end-line="3" selection-end-column="20" />
<state relative-caret-position="126">
<caret line="7" column="34" lean-forward="false" selection-start-line="7" selection-start-column="34" selection-end-line="7" selection-end-column="34" />
<folding />
</state>
</provider>
@ -40,38 +62,41 @@
<file leaf-file-name="todos_controller.rb" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/controllers/todos_controller.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="288">
<caret line="16" column="10" lean-forward="true" selection-start-line="16" selection-start-column="10" selection-end-line="16" selection-end-column="10" />
<state relative-caret-position="594">
<caret line="36" column="24" lean-forward="false" selection-start-line="36" selection-start-column="24" selection-end-line="36" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="application_controller.rb" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/app/controllers/application_controller.rb">
<file leaf-file-name="items_spec.rb" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/spec/requests/items_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="36">
<caret line="2" column="26" lean-forward="false" selection-start-line="2" selection-start-column="26" selection-end-line="2" selection-end-column="26" />
<state relative-caret-position="347">
<caret line="123" column="81" lean-forward="false" selection-start-line="123" selection-start-column="81" selection-end-line="123" selection-end-column="81" />
<folding>
<element signature="e#1051#1655#0" expanded="false" />
<element signature="e#2531#3269#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
</file>
<file leaf-file-name="authentication_controller.rb" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/controllers/authentication_controller.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="15" column="0" lean-forward="true" selection-start-line="15" selection-start-column="0" selection-end-line="15" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="response.rb" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/controllers/concerns/response.rb">
<file leaf-file-name="user.rb" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/app/models/user.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="72">
<caret line="4" column="3" lean-forward="true" selection-start-line="4" selection-start-column="3" selection-end-line="4" selection-end-column="3" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="exception_handler.rb" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/controllers/concerns/exception_handler.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="162">
<caret line="9" column="64" lean-forward="false" selection-start-line="9" selection-start-column="64" selection-end-line="9" selection-end-column="64" />
<state relative-caret-position="108">
<caret line="6" column="32" lean-forward="false" selection-start-line="6" selection-start-column="32" selection-end-line="6" selection-end-column="32" />
<folding />
</state>
</provider>
@ -85,7 +110,6 @@
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/Gemfile" />
<option value="$PROJECT_DIR$/spec/models/todo_spec.rb" />
<option value="$PROJECT_DIR$/spec/models/item_spec.rb" />
<option value="$PROJECT_DIR$/config/database.yml" />
@ -93,14 +117,32 @@
<option value="$PROJECT_DIR$/app/models/todo.rb" />
<option value="$PROJECT_DIR$/spec/factories/todos.rb" />
<option value="$PROJECT_DIR$/spec/factories/items.rb" />
<option value="$PROJECT_DIR$/spec/requests/todos_spec.rb" />
<option value="$PROJECT_DIR$/spec/support/request_spec_helper.rb" />
<option value="$PROJECT_DIR$/spec/rails_helper.rb" />
<option value="$PROJECT_DIR$/config/routes.rb" />
<option value="$PROJECT_DIR$/app/controllers/todos_controller.rb" />
<option value="$PROJECT_DIR$/app/controllers/concerns/response.rb" />
<option value="$PROJECT_DIR$/app/controllers/items_controller.rb" />
<option value="$PROJECT_DIR$/spec/models/user_spec.rb" />
<option value="$PROJECT_DIR$/spec/factories/users.rb" />
<option value="$PROJECT_DIR$/Gemfile" />
<option value="$PROJECT_DIR$/app/lib/json_web_token.rb" />
<option value="$PROJECT_DIR$/spec/auth/authorize_api_request_spec.rb" />
<option value="$PROJECT_DIR$/spec/support/controller_spec_helper.rb" />
<option value="$PROJECT_DIR$/spec/rails_helper.rb" />
<option value="$PROJECT_DIR$/app/controllers/concerns/exception_handler.rb" />
<option value="$PROJECT_DIR$/app/auth/authorize_api_request.rb" />
<option value="$PROJECT_DIR$/app/lib/message.rb" />
<option value="$PROJECT_DIR$/spec/auth/authenticate_user_spec.rb" />
<option value="$PROJECT_DIR$/app/auth/authenticate_user.rb" />
<option value="$PROJECT_DIR$/spec/requests/authentication_spec.rb" />
<option value="$PROJECT_DIR$/spec/requests/users_spec.rb" />
<option value="$PROJECT_DIR$/config/routes.rb" />
<option value="$PROJECT_DIR$/spec/controllers/application_controller_spec.rb" />
<option value="$PROJECT_DIR$/app/controllers/application_controller.rb" />
<option value="$PROJECT_DIR$/app/controllers/users_controller.rb" />
<option value="$PROJECT_DIR$/app/controllers/authentication_controller.rb" />
<option value="$PROJECT_DIR$/spec/requests/todos_spec.rb" />
<option value="$PROJECT_DIR$/app/controllers/todos_controller.rb" />
<option value="$PROJECT_DIR$/spec/requests/items_spec.rb" />
<option value="$PROJECT_DIR$/app/models/user.rb" />
</list>
</option>
</component>
@ -151,24 +193,12 @@
<item name="app" type="462c0819:PsiDirectoryNode" />
<item name="controllers" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="vereto-api" type="b2602c69:ProjectViewProjectNode" />
<item name="vereto-api" type="462c0819:PsiDirectoryNode" />
<item name="app" type="462c0819:PsiDirectoryNode" />
<item name="controllers" type="462c0819:PsiDirectoryNode" />
<item name="concerns" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="vereto-api" type="b2602c69:ProjectViewProjectNode" />
<item name="vereto-api" type="462c0819:PsiDirectoryNode" />
<item name="app" type="462c0819:PsiDirectoryNode" />
<item name="models" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="vereto-api" type="b2602c69:ProjectViewProjectNode" />
<item name="vereto-api" type="462c0819:PsiDirectoryNode" />
<item name="config" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
@ -309,16 +339,15 @@
<option name="presentableId" value="Default" />
<updated>1518771982661</updated>
<workItem from="1518771986536" duration="30000" />
<workItem from="1518772064427" duration="7202000" />
<workItem from="1518772064427" duration="14984000" />
</task>
<servers />
</component>
<component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="7232000" />
<option name="totallyTimeSpent" value="15014000" />
</component>
<component name="ToolWindowManager">
<frame x="0" y="28" width="1920" height="1026" extended-state="6" />
<editor active="true" />
<layout>
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.18643162" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
@ -328,7 +357,7 @@
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.33799785" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="true" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.33799785" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
@ -367,14 +396,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/Gemfile">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="198">
<caret line="11" column="25" lean-forward="false" selection-start-line="11" selection-start-column="25" selection-end-line="11" selection-end-column="25" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/models/todo_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="180">
@ -439,7 +460,7 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/factories/todos.rb">
<entry file="file://$PROJECT_DIR$/spec/support/request_spec_helper.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="108">
<caret line="6" column="3" lean-forward="false" selection-start-line="6" selection-start-column="3" selection-end-line="6" selection-end-column="3" />
@ -447,6 +468,14 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/models/user_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="180">
<caret line="10" column="54" lean-forward="false" selection-start-line="10" selection-start-column="54" selection-end-line="10" selection-end-column="54" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/factories/items.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="126">
@ -455,15 +484,7 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/controllers/items_controller.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/support/request_spec_helper.rb">
<entry file="file://$PROJECT_DIR$/spec/factories/todos.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="108">
<caret line="6" column="3" lean-forward="false" selection-start-line="6" selection-start-column="3" selection-end-line="6" selection-end-column="3" />
@ -471,26 +492,34 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/rails_helper.rb">
<entry file="file://$PROJECT_DIR$/spec/factories/users.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="396">
<caret line="46" column="50" lean-forward="false" selection-start-line="46" selection-start-column="50" selection-end-line="46" selection-end-column="50" />
<state relative-caret-position="72">
<caret line="4" column="20" lean-forward="false" selection-start-line="4" selection-start-column="20" selection-end-line="4" selection-end-column="20" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/requests/todos_spec.rb">
<entry file="file://$PROJECT_DIR$/app/controllers/items_controller.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="527">
<caret line="108" column="3" lean-forward="false" selection-start-line="108" selection-start-column="3" selection-end-line="108" selection-end-column="3" />
<state relative-caret-position="774">
<caret line="43" column="58" lean-forward="false" selection-start-line="43" selection-start-column="58" selection-end-line="43" selection-end-column="58" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/config/routes.rb">
<entry file="file://$PROJECT_DIR$/Gemfile">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="54">
<caret line="3" column="20" lean-forward="false" selection-start-line="3" selection-start-column="20" selection-end-line="3" selection-end-column="20" />
<state relative-caret-position="360">
<caret line="20" column="8" lean-forward="false" selection-start-line="20" selection-start-column="8" selection-end-line="20" selection-end-column="8" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/lib/json_web_token.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="360">
<caret line="20" column="3" lean-forward="false" selection-start-line="20" selection-start-column="3" selection-end-line="20" selection-end-column="3" />
<folding />
</state>
</provider>
@ -503,26 +532,169 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/rails_helper.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="347">
<caret line="47" column="37" lean-forward="false" selection-start-line="47" selection-start-column="37" selection-end-line="47" selection-end-column="37" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/controllers/concerns/exception_handler.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="162">
<caret line="9" column="64" lean-forward="false" selection-start-line="9" selection-start-column="64" selection-end-line="9" selection-end-column="64" />
<state relative-caret-position="252">
<caret line="14" column="47" lean-forward="false" selection-start-line="14" selection-start-column="47" selection-end-line="14" selection-end-column="47" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/lib/message.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="527">
<caret line="32" column="3" lean-forward="false" selection-start-line="32" selection-start-column="3" selection-end-line="32" selection-end-column="3" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/auth/authorize_api_request.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="491">
<caret line="37" column="63" lean-forward="false" selection-start-line="37" selection-start-column="63" selection-end-line="37" selection-end-column="63" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/auth/authenticate_user_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="527">
<caret line="31" column="3" lean-forward="false" selection-start-line="31" selection-start-column="3" selection-end-line="31" selection-end-column="3" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/support/controller_spec_helper.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="450">
<caret line="25" column="5" lean-forward="true" selection-start-line="25" selection-start-column="5" selection-end-line="25" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/auth/authorize_api_request_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="426">
<caret line="69" column="9" lean-forward="true" selection-start-line="69" selection-start-column="9" selection-end-line="69" selection-end-column="9" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/controllers/authentication_controller_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/requests/users_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="509">
<caret line="39" column="5" lean-forward="true" selection-start-line="39" selection-start-column="5" selection-end-line="39" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/auth/authenticate_user.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="342">
<caret line="19" column="77" lean-forward="true" selection-start-line="19" selection-start-column="77" selection-end-line="19" selection-end-column="77" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/requests/authentication_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="527">
<caret line="44" column="3" lean-forward="false" selection-start-line="44" selection-start-column="3" selection-end-line="44" selection-end-column="3" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/controllers/application_controller_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="540">
<caret line="30" column="3" lean-forward="false" selection-start-line="30" selection-start-column="3" selection-end-line="30" selection-end-column="3" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/controllers/users_controller.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="18">
<caret line="1" column="54" lean-forward="false" selection-start-line="1" selection-start-column="54" selection-end-line="1" selection-end-column="54" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/spec/requests/todos_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="347">
<caret line="109" column="69" lean-forward="false" selection-start-line="109" selection-start-column="69" selection-end-line="109" selection-end-column="69" />
<folding>
<element signature="e#360#734#0" expanded="false" />
<element signature="e#798#1441#0" expanded="false" />
<element signature="e#1690#1963#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/controllers/application_controller.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="198">
<caret line="11" column="73" lean-forward="false" selection-start-line="11" selection-start-column="73" selection-end-line="11" selection-end-column="73" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/config/routes.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="126">
<caret line="7" column="34" lean-forward="false" selection-start-line="7" selection-start-column="34" selection-end-line="7" selection-end-column="34" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/controllers/todos_controller.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="288">
<caret line="16" column="10" lean-forward="true" selection-start-line="16" selection-start-column="10" selection-end-line="16" selection-end-column="10" />
<state relative-caret-position="594">
<caret line="36" column="24" lean-forward="false" selection-start-line="36" selection-start-column="24" selection-end-line="36" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/controllers/application_controller.rb">
<entry file="file://$PROJECT_DIR$/spec/requests/items_spec.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="36">
<caret line="2" column="26" lean-forward="false" selection-start-line="2" selection-start-column="26" selection-end-line="2" selection-end-column="26" />
<state relative-caret-position="347">
<caret line="123" column="81" lean-forward="false" selection-start-line="123" selection-start-column="81" selection-end-line="123" selection-end-column="81" />
<folding>
<element signature="e#1051#1655#0" expanded="false" />
<element signature="e#2531#3269#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/controllers/authentication_controller.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="15" column="0" lean-forward="true" selection-start-line="15" selection-start-column="0" selection-end-line="15" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/models/user.rb">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="108">
<caret line="6" column="32" lean-forward="false" selection-start-line="6" selection-start-column="32" selection-end-line="6" selection-end-column="32" />
<folding />
</state>
</provider>

View file

@ -17,7 +17,8 @@ gem 'puma', '~> 3.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'bcrypt', '~> 3.1.7'
gem 'jwt'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

View file

@ -39,6 +39,7 @@ GEM
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (8.0.0)
bcrypt (3.1.11)
builder (3.2.3)
byebug (10.0.0)
concurrent-ruby (1.0.5)
@ -58,6 +59,7 @@ GEM
activesupport (>= 4.2.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
jwt (2.1.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
@ -150,10 +152,12 @@ PLATFORMS
ruby
DEPENDENCIES
bcrypt (~> 3.1.7)
byebug
database_cleaner
factory_girl_rails (~> 4.0)
faker
jwt
listen (>= 3.0.5, < 3.2)
mysql2 (>= 0.4.10)
puma (~> 3.7)

View file

@ -0,0 +1,22 @@
class AuthenticateUser
def initialize(email, password)
@email = email
@password = password
end
# Service entry point
def call
JsonWebToken.encode(user_id: user.id) if user
end
private
attr_reader :email, :password
def user
user = User.find_by(email: email)
return user if user && user.authenticate(password)
raise(ExceptionHandler::AuthenticationError, Message.invalid_credentials)
end
end

View file

@ -0,0 +1,41 @@
class AuthorizeApiRequest
def initialize(headers = {})
@headers = headers
end
# Service entry point - return valid user object
def call
{
user: user
}
end
private
attr_reader :headers
def user
# check if user is in the db
# memoize user object
@user ||= User.find(decoded_auth_token[:user_id]) if decoded_auth_token
# handle user not found
rescue ActiveRecord::RecordNotFound => e
raise(
ExceptionHandler::InvalidToken,
("#{Message.invalid_token} #{e.message}")
)
end
# decode auth token
def decoded_auth_token
@decoded_auth_token ||= JsonWebToken.decode(http_auth_header)
end
def http_auth_header
if headers['Authorization'].present?
return headers['Authorization'].split(' ').last
end
raise(ExceptionHandler::MissingToken, Message.missing_token)
end
end

View file

@ -1,4 +1,14 @@
class ApplicationController < ActionController::API
include Response
include ExceptionHandler
# called before every action on controllers
before_action :authorize_request
attr_reader :current_user
private
def authorize_request
@current_user = (AuthorizeApiRequest.new(request.headers).call)[:user]
end
end

View file

@ -0,0 +1,15 @@
class AuthenticationController < ApplicationController
skip_before_action :authorize_request, only: :authenticate
def authenticate
auth_token =
AuthenticateUser.new(auth_params[:email], auth_params[:password]).call
json_response(auth_token: auth_token)
end
private
def auth_params
params.permit(:email, :password)
end
end

View file

@ -1,14 +1,34 @@
# I made this file lel
module ExceptionHandler
extend ActiveSupport::Concern
# Define custom error subclasses - rescue catches `StandardErrors`
class AuthenticationError < StandardError; end
class MissingToken < StandardError; end
class InvalidToken < StandardError; end
included do
# Define custom handlers
rescue_from ActiveRecord::RecordInvalid, with: :four_twenty_two
rescue_from ExceptionHandler::AuthenticationError, with: :unauthorized_request
rescue_from ExceptionHandler::MissingToken, with: :four_twenty_two
rescue_from ExceptionHandler::InvalidToken, with: :four_twenty_two
rescue_from ActiveRecord::RecordNotFound do |e|
json_response({ message: e.message}, :not_found)
end
end
rescue_from ActiveRecord::RecordInvalid do |e|
json_response({ message: e.message}, :unprocessable_entity)
end
private
# JSON Resoinse with message; Status code 422 - unprocessable entity
def four_twenty_two(e)
json_response({ message: e.message}, :unprocessable_entity)
end
# JSON Response with message; Status code 401 - Unauthorized
def unauthorized_request(e)
json_response({ message: e.message }, :unauthorized)
end
end

View file

@ -1,2 +1,47 @@
class ItemsController < ApplicationController
before_action :set_todo
before_action :set_todo_item, only: [:show, :update, :destroy]
# GET /todos/:todo_id/items
def index
json_response(@todo.items)
end
# GET /todos/:todo_id/items/:id
def show
json_response(@item)
end
# POST /todos/:todo_id/items
def create
@todo.items.create!(item_params)
json_response(@todo, :created)
end
# PUT /todos/:todo_id/items/:d
def update
@item.update(item_params)
head :no_content
end
# DELETE /todos/:todo_id/items/:id
def destroy
@item.destroy
head :no_content
end
private
def item_params
params.permit(:name, :done)
end
def set_todo
@todo = Todo.find(params[:todo_id])
end
def set_todo_item
@item = @todo.items.find_by!(id: params[:id]) if @todo
end
end

View file

@ -3,13 +3,13 @@ class TodosController < ApplicationController
# GET /todos
def index
@todos = Todo.all
@todos = current_user.todos
json_response(@todos)
end
# POST /todos
def create
@todo = Todo.create!(todo_params)
@todo = current_user.todos.create!(todo_params)
json_response(@todo, :created)
end
@ -34,7 +34,7 @@ class TodosController < ApplicationController
def todo_params
# whitelist params
params.permit(:title, :created_by)
params.permit(:title)
end
def set_todo

View file

@ -0,0 +1,22 @@
class UsersController < ApplicationController
skip_before_action :authorize_request, only: :create
# POST /signup
# return authenticated token upon signup
def create
user = User.create!(user_params)
auth_token = AuthenticateUser.new(user.email, user.password).call
response = { message: Message.account_created, auth_token: auth_token }
json_response(response, :created)
end
private
def user_params
params.permit(
:name,
:email,
:password,
:password_confirmation
)
end
end

21
app/lib/json_web_token.rb Normal file
View file

@ -0,0 +1,21 @@
class JsonWebToken
# secret to encode and decode token
HMAC_SECRET = Rails.application.secrets.secret_key_base
def self.encode(payload, exp = 24.hours.from_now)
# set expiry to 24 hours from creation time
payload[:exp] = exp.to_i
# sign token with application secret
JWT.encode(payload, HMAC_SECRET)
end
def self.decode(token)
# get payload; first index in decoded Array
body = JWT.decode(token, HMAC_SECRET)[0]
HashWithIndifferentAccess.new body
# rescue from all decode errors
rescue JWT::DecodeError => e
# raise custom error to be handled by custom handler
raise ExceptionHandler::InvalidToken, e.message
end
end

33
app/lib/message.rb Normal file
View file

@ -0,0 +1,33 @@
class Message
def self.not_found(record = 'record')
"Sorry, #{record} not found."
end
def self.invalid_credentials
'Invalid credentials'
end
def self.invalid_token
'Invalid token'
end
def self.missing_token
'Missing token'
end
def self.unauthorized
'Unauthorized request'
end
def self.account_created
'Account created successfully'
end
def self.account_not_created
'Account could not be created'
end
def self.expired_token
'Sorry, your token has expired. Please login to continue.'
end
end

8
app/models/user.rb Normal file
View file

@ -0,0 +1,8 @@
class User < ApplicationRecord
has_secure_password
has_many :todos, foreign_key: :created_by
validates_presence_of :name, :email, :password_digest
validates_uniqueness_of :email
end

View file

@ -3,4 +3,7 @@ Rails.application.routes.draw do
resources :todos do
resources :items
end
post 'auth/login', to: 'authentication#authenticate'
post 'signup', to: 'users#create'
end

View file

@ -0,0 +1,11 @@
class CreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :password_digest
t.timestamps
end
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180216101247) do
ActiveRecord::Schema.define(version: 20180216131546) do
create_table "items", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "name"
@ -28,5 +28,13 @@ ActiveRecord::Schema.define(version: 20180216101247) do
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "name"
t.string "email"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "items", "todos"
end

View file

@ -0,0 +1,32 @@
require 'rails_helper'
RSpec.describe AuthenticateUser do
# create test user
let(:user) { create(:user) }
# valid request subject
subject(:valid_auth_obj) { described_class.new(user.email, user.password) }
# invalid request subject
subject(:invalid_auth_obj) { described_class.new('foo', 'bar') }
# Test suite for AuthenticateUser#call
describe '#call' do
# return token when valid request
context 'when valid credentials' do
it 'returns an auth token' do
token = valid_auth_obj.call
expect(token).not_to be_nil
end
end
# raise Authentication Error when invalid request
context 'when invalid credentials' do
it 'raises an authentication error' do
expect { invalid_auth_obj.call }
.to raise_error(
ExceptionHandler::AuthenticationError,
/Invalid credentials/
)
end
end
end
end

View file

@ -0,0 +1,73 @@
# spec/auth/authorize_api_request_spec.rb
require 'rails_helper'
RSpec.describe AuthorizeApiRequest do
# Create test user
let(:user) { create(:user) }
# Mock `Authorization` header
let(:header) { { 'Authorization' => token_generator(user.id) } }
# Invalid request subject
subject(:invalid_request_obj) { described_class.new({}) }
# Valid request subject
subject(:request_obj) { described_class.new(header) }
# Test Suite for AuthorizeApiRequest#call
# This is our entry point into the service class
describe '#call' do
# returns user object when request is valid
context 'when valid request' do
it 'returns user object' do
result = request_obj.call
expect(result[:user]).to eq(user)
end
end
# returns error message when invalid request
context 'when invalid request' do
context 'when missing token' do
it 'raises a MissingToken error' do
expect { invalid_request_obj.call }
.to raise_error(ExceptionHandler::MissingToken, 'Missing token')
end
end
context 'when invalid token' do
subject(:invalid_request_obj) do
# custom helper method `token_generator`
described_class.new('Authorization' => token_generator(5))
end
it 'raises an InvalidToken error' do
expect { invalid_request_obj.call }
.to raise_error(ExceptionHandler::InvalidToken, /Invalid token/)
end
end
context 'when token is expired' do
let(:header) { { 'Authorization' => expired_token_generator(user.id) } }
subject(:request_obj) { described_class.new(header) }
it 'raises ExceptionHandler::ExpiredSignature error' do
expect { request_obj.call }
.to raise_error(
ExceptionHandler::InvalidToken,
/Signature has expired/
)
end
end
context 'fake token' do
let(:header) { { 'Authorization' => 'foobar' } }
subject(:invalid_request_obj) { described_class.new(header) }
it 'handles JWT::DecodeError' do
expect { invalid_request_obj.call }
.to raise_error(
ExceptionHandler::InvalidToken,
/Not enough or too many segments/
)
end
end
end
end
end

View file

@ -0,0 +1,31 @@
require "rails_helper"
RSpec.describe ApplicationController, type: :controller do
# create test user
let!(:user) { create(:user) }
# set headers for authorization
let(:headers) { { 'Authorization' => token_generator(user.id) } }
let(:invalid_headers) { { 'Authorization' => nil } }
describe "#authorize_request" do
context "when auth token is passed" do
before { allow(request).to receive(:headers).and_return(headers) }
# private method authorize_request returns current user
it "sets the current user" do
expect(subject.instance_eval { authorize_request }).to eq(user)
end
end
context "when auth token is not passed" do
before do
allow(request).to receive(:headers).and_return(invalid_headers)
end
it "raises MissingToken error" do
expect { subject.instance_eval { authorize_request } }.
to raise_error(ExceptionHandler::MissingToken, /Missing token/)
end
end
end
end

View file

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe AuthenticationController, type: :controller do
end

View file

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe UsersController, type: :controller do
end

7
spec/factories/users.rb Normal file
View file

@ -0,0 +1,7 @@
FactoryGirl.define do
factory :user do
name { Faker::Name.name }
email 'fooooooo@bar.com'
password 'foobar'
end
end

12
spec/models/user_spec.rb Normal file
View file

@ -0,0 +1,12 @@
require 'rails_helper'
RSpec.describe User, type: :model do
# Association test
# ensure User model has a 1:m relationship with the Todo model
it { should have_many(:todos) }
# Validation tests
# ensure name, email and password_digest are present before save
it { should validate_presence_of(:name) }
it { should validate_presence_of(:email) }
it { should validate_presence_of(:password_digest) }
end

View file

@ -44,7 +44,8 @@ RSpec.configure do |config|
config.use_transactional_fixtures = true
# add `FactoryGirl` methods
config.include FactoryGirl::Syntax::Methods
config.include RequestSpecHelper, type: :request
config.include RequestSpecHelper
config.include ControllerSpecHelper
# start by truncating all the tables but then use the faster transaction strategy the rest of the time.
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)

View file

@ -0,0 +1,45 @@
require 'rails_helper'
RSpec.describe 'Authentication', type: :request do
# Authentication test suite
describe 'POST /auth/login' do
# create test user
let!(:user) { create(:user) }
# set headers for authorization
let(:headers) { valid_headers.except('Authorization') }
# set test valid and invalid credentials
let(:valid_credentials) do
{
email: user.email,
password: user.password
}.to_json
end
let(:invalid_credentials) do
{
email: Faker::Internet.email,
password: Faker::Internet.password
}.to_json
end
# set request.headers to our custon headers
# before { allow(request).to receive(:headers).and_return(headers) }
# returns auth token when request is valid
context 'When request is valid' do
before { post '/auth/login', params: valid_credentials, headers: headers }
it 'returns an authentication token' do
expect(json['auth_token']).not_to be_nil
end
end
# returns failure message when request is invalid
context 'When request is invalid' do
before { post '/auth/login', params: invalid_credentials, headers: headers }
it 'returns a failure message' do
expect(json['message']).to match(/Invalid credentials/)
end
end
end
end

View file

@ -0,0 +1,130 @@
require 'rails_helper'
RSpec.describe 'Items API' do
# Initialize the test data
let(:user) { create(:user) }
let!(:todo) { create(:todo, created_by: user.id) }
let!(:items) { create_list(:item, 20, todo_id: todo.id) }
let(:todo_id) { todo.id }
let(:id) { items.first.id }
let(:headers) { valid_headers }
describe 'GET /todos/:todo_id/items' do
before { get "/todos/#{todo_id}/items", params: {}, headers: headers }
context 'when todo exists' do
it 'returns status code 200' do
expect(response).to have_http_status(200)
end
it 'returns all todo items' do
expect(json.size).to eq(20)
end
end
context 'when todo does not exist' do
let(:todo_id) { 0 }
it 'returns status code 404' do
expect(response).to have_http_status(404)
end
it 'returns a not found message' do
expect(response.body).to match(/Couldn't find Todo/)
end
end
end
# Test suite for GET /todos/:todo_id/items/:id
describe 'GET /todos/:todo_id/items/:id' do
before { get "/todos/#{todo_id}/items/#{id}", params: {}, headers: headers }
context 'when todo item exists' do
it 'returns status code 200' do
expect(response).to have_http_status(200)
end
it 'returns the item' do
expect(json['id']).to eq(id)
end
end
context 'when todo item does not exist' do
let(:id) { 0 }
it 'returns status code 404' do
expect(response).to have_http_status(404)
end
it 'returns a not found message' do
expect(response.body).to match(/Couldn't find Item/)
end
end
end
# Test suite for PUT /todos/:todo_id/items
describe 'POST /todos/:todo_id/items' do
let(:valid_attributes) { { name: 'Visit Narnia', done: false }.to_json }
context 'when request attributes are valid' do
before { post "/todos/#{todo_id}/items", params: valid_attributes, headers: headers }
it 'returns status code 201' do
expect(response).to have_http_status(201)
end
end
context 'when an invalid request' do
before { post "/todos/#{todo_id}/items", params: {}, headers: headers }
it 'returns status code 422' do
expect(response).to have_http_status(422)
end
it 'returns a failure message' do
expect(response.body).to match(/Validation failed: Name can't be blank/)
end
end
end
# Test suite for PUT /todos/:todo_id/items/:id
describe 'PUT /todos/:todo_id/items/:id' do
let(:valid_attributes) { { name: 'Mozart' }.to_json }
before do
put "/todos/#{todo_id}/items/#{id}", params: valid_attributes, headers: headers
end
context 'when item exists' do
it 'returns status code 204' do
expect(response).to have_http_status(204)
end
it 'updates the item' do
updated_item = Item.find(id)
expect(updated_item.name).to match(/Mozart/)
end
end
context 'when the item does not exist' do
let(:id) { 0 }
it 'returns status code 404' do
expect(response).to have_http_status(404)
end
it 'returns a not found message' do
expect(response.body).to match(/Couldn't find Item/)
end
end
end
# Test suite for DELETE /todos/:id
describe 'DELETE /todos/:id' do
before { delete "/todos/#{todo_id}/items/#{id}", params: {}, headers: headers }
it 'returns status code 204' do
expect(response).to have_http_status(204)
end
end
end

View file

@ -2,14 +2,17 @@
require 'rails_helper'
RSpec.describe 'Todos API', type: :request do
# initialize test data
let!(:todos) { create_list(:todo, 10) }
# add todos owner
let(:user) { create(:user) }
let!(:todos) { create_list(:todo, 10, created_by: user.id) }
let(:todo_id) { todos.first.id }
# authorize request
let(:headers) { valid_headers }
# Test suite for GET /todos
describe 'GET /todos' do
# make HTTP get request before each example
before { get '/todos' }
before { get '/todos', params: {}, headers: headers }
it 'returns todos' do
# Note `json` is a custom helper to parse JSON responses
@ -24,7 +27,7 @@ RSpec.describe 'Todos API', type: :request do
# Test suite for GET /todos/:id
describe 'GET /todos/:id' do
before { get "/todos/#{todo_id}" }
before { get "/todos/#{todo_id}", params: {}, headers: headers }
context 'when the record exists' do
it 'returns the todo' do
@ -53,10 +56,13 @@ RSpec.describe 'Todos API', type: :request do
# Test suite for POST /todos
describe 'POST /todos' do
# valid payload
let(:valid_attributes) { { title: 'Learn Elm', created_by: '1' } }
let(:valid_attributes) do
# send json payload
{ title: 'Learn Elm', created_by: user.id.to_s }.to_json
end
context 'when the request is valid' do
before { post '/todos', params: valid_attributes }
before { post '/todos', params: valid_attributes, headers: headers }
it 'creates a todo' do
expect(json['title']).to eq('Learn Elm')
@ -68,25 +74,26 @@ RSpec.describe 'Todos API', type: :request do
end
context 'when the request is invalid' do
before { post '/todos', params: { title: 'Foobar' } }
let(:invalid_attributes) { { title: nil }.to_json }
before { post '/todos', params: invalid_attributes, headers: headers }
it 'returns status code 422' do
expect(response).to have_http_status(422)
end
it 'returns a validation failure message' do
expect(response.body)
.to match(/Validation failed: Created by can't be blank/)
expect(json['message'])
.to match(/Validation failed: Title can't be blank/)
end
end
end
# Test suite for PUT /todos/:id
describe 'PUT /todos/:id' do
let(:valid_attributes) { { title: 'Shopping' } }
let(:valid_attributes) { { title: 'Shopping' }.to_json }
context 'when the record exists' do
before { put "/todos/#{todo_id}", params: valid_attributes }
before { put "/todos/#{todo_id}", params: valid_attributes, headers: headers }
it 'updates the record' do
expect(response.body).to be_empty
@ -100,7 +107,7 @@ RSpec.describe 'Todos API', type: :request do
# Test suite for DELETE /todos/:id
describe 'DELETE /todos/:id' do
before { delete "/todos/#{todo_id}" }
before { delete "/todos/#{todo_id}", params: {}, headers: headers }
it 'returns status code 204' do
expect(response).to have_http_status(204)

View file

@ -0,0 +1,41 @@
require 'rails_helper'
RSpec.describe 'Users API', type: :request do
let(:user) { build(:user) }
let(:headers) { valid_headers.except('Authorization') }
let(:valid_attributes) do
attributes_for(:user, password_confirmation: user.password)
end
# User signup test suite
describe 'POST /signup' do
context 'when valid request' do
before { post '/signup', params: valid_attributes.to_json, headers: headers }
it 'creates a new user' do
expect(response).to have_http_status(201)
end
it 'returns success message' do
expect(json['message']).to match(/Account created successfully/)
end
it 'returns an authentication token' do
expect(json['auth_token']).not_to be_nil
end
end
context 'when invalid request' do
before { post '/signup', params: {}, headers: headers }
it 'does not create a new user' do
expect(response).to have_http_status(422)
end
it 'returns failure message' do
expect(json['message'])
.to match(/Validation failed: Password can't be blank, Name can't be blank, Email can't be blank, Password digest can't be blank/)
end
end
end
end

View file

@ -0,0 +1,28 @@
# spec/support/controller_spec_helper.rb
module ControllerSpecHelper
# generate tokens from user id
def token_generator(user_id)
JsonWebToken.encode(user_id: user_id)
end
# generate expired tokens from user id
def expired_token_generator(user_id)
JsonWebToken.encode({ user_id: user_id }, (Time.now.to_i - 10))
end
# return valid headers
def valid_headers
{
"Authorization" => token_generator(user.id),
"Content-Type" => "application/json"
}
end
# return invalid headers
def invalid_headers
{
"Authorization" => nil,
"Content-Type" => "application/json"
}
end
end