JWT complete
This commit is contained in:
parent
976488dbe1
commit
56f8d8dd6a
31 changed files with 954 additions and 102 deletions
1
.idea/vereto-api.iml
generated
1
.idea/vereto-api.iml
generated
|
|
@ -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="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 (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="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="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="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" />
|
<orderEntry type="library" scope="PROVIDED" name="tzinfo (v1.2.5, rbenv: 2.5.0) [gem]" level="application" />
|
||||||
|
|
|
||||||
332
.idea/workspace.xml
generated
332
.idea/workspace.xml
generated
|
|
@ -2,14 +2,36 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="42443dfa-4405-4cad-b0d1-6c57eb86e644" name="Default" comment="">
|
<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$/app/auth/authenticate_user.rb" />
|
||||||
<change beforePath="" afterPath="$PROJECT_DIR$/spec/support/request_spec_helper.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$/.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/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$/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$/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/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" />
|
<change beforePath="$PROJECT_DIR$/spec/requests/todos_spec.rb" afterPath="$PROJECT_DIR$/spec/requests/todos_spec.rb" />
|
||||||
</list>
|
</list>
|
||||||
<ignored path="$PROJECT_DIR$/.bundle/" />
|
<ignored path="$PROJECT_DIR$/.bundle/" />
|
||||||
|
|
@ -30,8 +52,8 @@
|
||||||
<file leaf-file-name="routes.rb" pinned="false" current-in-tab="false">
|
<file leaf-file-name="routes.rb" pinned="false" current-in-tab="false">
|
||||||
<entry file="file://$PROJECT_DIR$/config/routes.rb">
|
<entry file="file://$PROJECT_DIR$/config/routes.rb">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="54">
|
<state relative-caret-position="126">
|
||||||
<caret line="3" column="20" lean-forward="false" selection-start-line="3" selection-start-column="20" selection-end-line="3" selection-end-column="20" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
@ -40,38 +62,41 @@
|
||||||
<file leaf-file-name="todos_controller.rb" pinned="false" current-in-tab="false">
|
<file leaf-file-name="todos_controller.rb" pinned="false" current-in-tab="false">
|
||||||
<entry file="file://$PROJECT_DIR$/app/controllers/todos_controller.rb">
|
<entry file="file://$PROJECT_DIR$/app/controllers/todos_controller.rb">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="288">
|
<state relative-caret-position="594">
|
||||||
<caret line="16" column="10" lean-forward="true" selection-start-line="16" selection-start-column="10" selection-end-line="16" selection-end-column="10" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
</file>
|
</file>
|
||||||
<file leaf-file-name="application_controller.rb" pinned="false" current-in-tab="true">
|
<file leaf-file-name="items_spec.rb" pinned="false" current-in-tab="false">
|
||||||
<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">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="36">
|
<state relative-caret-position="347">
|
||||||
<caret line="2" column="26" lean-forward="false" selection-start-line="2" selection-start-column="26" selection-end-line="2" selection-end-column="26" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
</file>
|
</file>
|
||||||
<file leaf-file-name="response.rb" pinned="false" current-in-tab="false">
|
<file leaf-file-name="user.rb" pinned="false" current-in-tab="true">
|
||||||
<entry file="file://$PROJECT_DIR$/app/controllers/concerns/response.rb">
|
<entry file="file://$PROJECT_DIR$/app/models/user.rb">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="72">
|
<state relative-caret-position="108">
|
||||||
<caret line="4" column="3" lean-forward="true" selection-start-line="4" selection-start-column="3" selection-end-line="4" selection-end-column="3" />
|
<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>
|
|
||||||
</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" />
|
|
||||||
<folding />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
@ -85,7 +110,6 @@
|
||||||
<component name="IdeDocumentHistory">
|
<component name="IdeDocumentHistory">
|
||||||
<option name="CHANGED_PATHS">
|
<option name="CHANGED_PATHS">
|
||||||
<list>
|
<list>
|
||||||
<option value="$PROJECT_DIR$/Gemfile" />
|
|
||||||
<option value="$PROJECT_DIR$/spec/models/todo_spec.rb" />
|
<option value="$PROJECT_DIR$/spec/models/todo_spec.rb" />
|
||||||
<option value="$PROJECT_DIR$/spec/models/item_spec.rb" />
|
<option value="$PROJECT_DIR$/spec/models/item_spec.rb" />
|
||||||
<option value="$PROJECT_DIR$/config/database.yml" />
|
<option value="$PROJECT_DIR$/config/database.yml" />
|
||||||
|
|
@ -93,14 +117,32 @@
|
||||||
<option value="$PROJECT_DIR$/app/models/todo.rb" />
|
<option value="$PROJECT_DIR$/app/models/todo.rb" />
|
||||||
<option value="$PROJECT_DIR$/spec/factories/todos.rb" />
|
<option value="$PROJECT_DIR$/spec/factories/todos.rb" />
|
||||||
<option value="$PROJECT_DIR$/spec/factories/items.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/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/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/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/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>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|
@ -151,24 +193,12 @@
|
||||||
<item name="app" type="462c0819:PsiDirectoryNode" />
|
<item name="app" type="462c0819:PsiDirectoryNode" />
|
||||||
<item name="controllers" type="462c0819:PsiDirectoryNode" />
|
<item name="controllers" type="462c0819:PsiDirectoryNode" />
|
||||||
</path>
|
</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>
|
<path>
|
||||||
<item name="vereto-api" type="b2602c69:ProjectViewProjectNode" />
|
<item name="vereto-api" type="b2602c69:ProjectViewProjectNode" />
|
||||||
<item name="vereto-api" type="462c0819:PsiDirectoryNode" />
|
<item name="vereto-api" type="462c0819:PsiDirectoryNode" />
|
||||||
<item name="app" type="462c0819:PsiDirectoryNode" />
|
<item name="app" type="462c0819:PsiDirectoryNode" />
|
||||||
<item name="models" type="462c0819:PsiDirectoryNode" />
|
<item name="models" type="462c0819:PsiDirectoryNode" />
|
||||||
</path>
|
</path>
|
||||||
<path>
|
|
||||||
<item name="vereto-api" type="b2602c69:ProjectViewProjectNode" />
|
|
||||||
<item name="vereto-api" type="462c0819:PsiDirectoryNode" />
|
|
||||||
<item name="config" type="462c0819:PsiDirectoryNode" />
|
|
||||||
</path>
|
|
||||||
</expand>
|
</expand>
|
||||||
<select />
|
<select />
|
||||||
</subPane>
|
</subPane>
|
||||||
|
|
@ -309,16 +339,15 @@
|
||||||
<option name="presentableId" value="Default" />
|
<option name="presentableId" value="Default" />
|
||||||
<updated>1518771982661</updated>
|
<updated>1518771982661</updated>
|
||||||
<workItem from="1518771986536" duration="30000" />
|
<workItem from="1518771986536" duration="30000" />
|
||||||
<workItem from="1518772064427" duration="7202000" />
|
<workItem from="1518772064427" duration="14984000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TimeTrackingManager">
|
<component name="TimeTrackingManager">
|
||||||
<option name="totallyTimeSpent" value="7232000" />
|
<option name="totallyTimeSpent" value="15014000" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ToolWindowManager">
|
<component name="ToolWindowManager">
|
||||||
<frame x="0" y="28" width="1920" height="1026" extended-state="6" />
|
<frame x="0" y="28" width="1920" height="1026" extended-state="6" />
|
||||||
<editor active="true" />
|
|
||||||
<layout>
|
<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="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" />
|
<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="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="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="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="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="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" />
|
<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>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</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">
|
<entry file="file://$PROJECT_DIR$/spec/models/todo_spec.rb">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="180">
|
<state relative-caret-position="180">
|
||||||
|
|
@ -439,7 +460,7 @@
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</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">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="108">
|
<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" />
|
<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>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</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">
|
<entry file="file://$PROJECT_DIR$/spec/factories/items.rb">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="126">
|
<state relative-caret-position="126">
|
||||||
|
|
@ -455,15 +484,7 @@
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/app/controllers/items_controller.rb">
|
<entry file="file://$PROJECT_DIR$/spec/factories/todos.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">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="108">
|
<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" />
|
<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>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</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">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="396">
|
<state relative-caret-position="72">
|
||||||
<caret line="46" column="50" lean-forward="false" selection-start-line="46" selection-start-column="50" selection-end-line="46" selection-end-column="50" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</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">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="527">
|
<state relative-caret-position="774">
|
||||||
<caret line="108" column="3" lean-forward="false" selection-start-line="108" selection-start-column="3" selection-end-line="108" selection-end-column="3" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/config/routes.rb">
|
<entry file="file://$PROJECT_DIR$/Gemfile">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="54">
|
<state relative-caret-position="360">
|
||||||
<caret line="3" column="20" lean-forward="false" selection-start-line="3" selection-start-column="20" selection-end-line="3" selection-end-column="20" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
@ -503,26 +532,169 @@
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</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">
|
<entry file="file://$PROJECT_DIR$/app/controllers/concerns/exception_handler.rb">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="162">
|
<state relative-caret-position="252">
|
||||||
<caret line="9" column="64" lean-forward="false" selection-start-line="9" selection-start-column="64" selection-end-line="9" selection-end-column="64" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/app/controllers/todos_controller.rb">
|
<entry file="file://$PROJECT_DIR$/app/controllers/todos_controller.rb">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="288">
|
<state relative-caret-position="594">
|
||||||
<caret line="16" column="10" lean-forward="true" selection-start-line="16" selection-start-column="10" selection-end-line="16" selection-end-column="10" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</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">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="36">
|
<state relative-caret-position="347">
|
||||||
<caret line="2" column="26" lean-forward="false" selection-start-line="2" selection-start-column="26" selection-end-line="2" selection-end-column="26" />
|
<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 />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
|
||||||
3
Gemfile
3
Gemfile
|
|
@ -17,7 +17,8 @@ gem 'puma', '~> 3.7'
|
||||||
# Use Redis adapter to run Action Cable in production
|
# Use Redis adapter to run Action Cable in production
|
||||||
# gem 'redis', '~> 4.0'
|
# gem 'redis', '~> 4.0'
|
||||||
# Use ActiveModel has_secure_password
|
# Use ActiveModel has_secure_password
|
||||||
# gem 'bcrypt', '~> 3.1.7'
|
gem 'bcrypt', '~> 3.1.7'
|
||||||
|
gem 'jwt'
|
||||||
|
|
||||||
# Use Capistrano for deployment
|
# Use Capistrano for deployment
|
||||||
# gem 'capistrano-rails', group: :development
|
# gem 'capistrano-rails', group: :development
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ GEM
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
arel (8.0.0)
|
arel (8.0.0)
|
||||||
|
bcrypt (3.1.11)
|
||||||
builder (3.2.3)
|
builder (3.2.3)
|
||||||
byebug (10.0.0)
|
byebug (10.0.0)
|
||||||
concurrent-ruby (1.0.5)
|
concurrent-ruby (1.0.5)
|
||||||
|
|
@ -58,6 +59,7 @@ GEM
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
i18n (0.9.5)
|
i18n (0.9.5)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
|
jwt (2.1.0)
|
||||||
listen (3.1.5)
|
listen (3.1.5)
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
rb-inotify (~> 0.9, >= 0.9.7)
|
||||||
|
|
@ -150,10 +152,12 @@ PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
bcrypt (~> 3.1.7)
|
||||||
byebug
|
byebug
|
||||||
database_cleaner
|
database_cleaner
|
||||||
factory_girl_rails (~> 4.0)
|
factory_girl_rails (~> 4.0)
|
||||||
faker
|
faker
|
||||||
|
jwt
|
||||||
listen (>= 3.0.5, < 3.2)
|
listen (>= 3.0.5, < 3.2)
|
||||||
mysql2 (>= 0.4.10)
|
mysql2 (>= 0.4.10)
|
||||||
puma (~> 3.7)
|
puma (~> 3.7)
|
||||||
|
|
|
||||||
22
app/auth/authenticate_user.rb
Normal file
22
app/auth/authenticate_user.rb
Normal 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
|
||||||
41
app/auth/authorize_api_request.rb
Normal file
41
app/auth/authorize_api_request.rb
Normal 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
|
||||||
|
|
@ -1,4 +1,14 @@
|
||||||
class ApplicationController < ActionController::API
|
class ApplicationController < ActionController::API
|
||||||
include Response
|
include Response
|
||||||
include ExceptionHandler
|
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
|
end
|
||||||
|
|
|
||||||
15
app/controllers/authentication_controller.rb
Normal file
15
app/controllers/authentication_controller.rb
Normal 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
|
||||||
|
|
@ -1,14 +1,34 @@
|
||||||
|
# I made this file lel
|
||||||
module ExceptionHandler
|
module ExceptionHandler
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
# Define custom error subclasses - rescue catches `StandardErrors`
|
||||||
|
class AuthenticationError < StandardError; end
|
||||||
|
class MissingToken < StandardError; end
|
||||||
|
class InvalidToken < StandardError; end
|
||||||
|
|
||||||
included do
|
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|
|
rescue_from ActiveRecord::RecordNotFound do |e|
|
||||||
json_response({ message: e.message}, :not_found)
|
json_response({ message: e.message}, :not_found)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordInvalid do |e|
|
private
|
||||||
json_response({ message: e.message}, :unprocessable_entity)
|
|
||||||
end
|
# 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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -1,2 +1,47 @@
|
||||||
class ItemsController < ApplicationController
|
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
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@ class TodosController < ApplicationController
|
||||||
|
|
||||||
# GET /todos
|
# GET /todos
|
||||||
def index
|
def index
|
||||||
@todos = Todo.all
|
@todos = current_user.todos
|
||||||
json_response(@todos)
|
json_response(@todos)
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST /todos
|
# POST /todos
|
||||||
def create
|
def create
|
||||||
@todo = Todo.create!(todo_params)
|
@todo = current_user.todos.create!(todo_params)
|
||||||
json_response(@todo, :created)
|
json_response(@todo, :created)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -34,7 +34,7 @@ class TodosController < ApplicationController
|
||||||
|
|
||||||
def todo_params
|
def todo_params
|
||||||
# whitelist params
|
# whitelist params
|
||||||
params.permit(:title, :created_by)
|
params.permit(:title)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_todo
|
def set_todo
|
||||||
|
|
|
||||||
22
app/controllers/users_controller.rb
Normal file
22
app/controllers/users_controller.rb
Normal 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
21
app/lib/json_web_token.rb
Normal 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
33
app/lib/message.rb
Normal 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
8
app/models/user.rb
Normal 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
|
||||||
|
|
@ -3,4 +3,7 @@ Rails.application.routes.draw do
|
||||||
resources :todos do
|
resources :todos do
|
||||||
resources :items
|
resources :items
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post 'auth/login', to: 'authentication#authenticate'
|
||||||
|
post 'signup', to: 'users#create'
|
||||||
end
|
end
|
||||||
|
|
|
||||||
11
db/migrate/20180216131546_create_users.rb
Normal file
11
db/migrate/20180216131546_create_users.rb
Normal 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
|
||||||
10
db/schema.rb
10
db/schema.rb
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# 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|
|
create_table "items", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
|
||||||
t.string "name"
|
t.string "name"
|
||||||
|
|
@ -28,5 +28,13 @@ ActiveRecord::Schema.define(version: 20180216101247) do
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
end
|
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"
|
add_foreign_key "items", "todos"
|
||||||
end
|
end
|
||||||
|
|
|
||||||
32
spec/auth/authenticate_user_spec.rb
Normal file
32
spec/auth/authenticate_user_spec.rb
Normal 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
|
||||||
73
spec/auth/authorize_api_request_spec.rb
Normal file
73
spec/auth/authorize_api_request_spec.rb
Normal 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
|
||||||
31
spec/controllers/application_controller_spec.rb
Normal file
31
spec/controllers/application_controller_spec.rb
Normal 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
|
||||||
5
spec/controllers/authentication_controller_spec.rb
Normal file
5
spec/controllers/authentication_controller_spec.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe AuthenticationController, type: :controller do
|
||||||
|
|
||||||
|
end
|
||||||
5
spec/controllers/users_controller_spec.rb
Normal file
5
spec/controllers/users_controller_spec.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe UsersController, type: :controller do
|
||||||
|
|
||||||
|
end
|
||||||
7
spec/factories/users.rb
Normal file
7
spec/factories/users.rb
Normal 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
12
spec/models/user_spec.rb
Normal 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
|
||||||
|
|
@ -44,7 +44,8 @@ RSpec.configure do |config|
|
||||||
config.use_transactional_fixtures = true
|
config.use_transactional_fixtures = true
|
||||||
# add `FactoryGirl` methods
|
# add `FactoryGirl` methods
|
||||||
config.include FactoryGirl::Syntax::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.
|
# start by truncating all the tables but then use the faster transaction strategy the rest of the time.
|
||||||
config.before(:suite) do
|
config.before(:suite) do
|
||||||
DatabaseCleaner.clean_with(:truncation)
|
DatabaseCleaner.clean_with(:truncation)
|
||||||
|
|
|
||||||
45
spec/requests/authentication_spec.rb
Normal file
45
spec/requests/authentication_spec.rb
Normal 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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -2,14 +2,17 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe 'Todos API', type: :request do
|
RSpec.describe 'Todos API', type: :request do
|
||||||
# initialize test data
|
# add todos owner
|
||||||
let!(:todos) { create_list(:todo, 10) }
|
let(:user) { create(:user) }
|
||||||
|
let!(:todos) { create_list(:todo, 10, created_by: user.id) }
|
||||||
let(:todo_id) { todos.first.id }
|
let(:todo_id) { todos.first.id }
|
||||||
|
# authorize request
|
||||||
|
let(:headers) { valid_headers }
|
||||||
|
|
||||||
# Test suite for GET /todos
|
# Test suite for GET /todos
|
||||||
describe 'GET /todos' do
|
describe 'GET /todos' do
|
||||||
# make HTTP get request before each example
|
# make HTTP get request before each example
|
||||||
before { get '/todos' }
|
before { get '/todos', params: {}, headers: headers }
|
||||||
|
|
||||||
it 'returns todos' do
|
it 'returns todos' do
|
||||||
# Note `json` is a custom helper to parse JSON responses
|
# 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
|
# Test suite for GET /todos/:id
|
||||||
describe 'GET /todos/:id' do
|
describe 'GET /todos/:id' do
|
||||||
before { get "/todos/#{todo_id}" }
|
before { get "/todos/#{todo_id}", params: {}, headers: headers }
|
||||||
|
|
||||||
context 'when the record exists' do
|
context 'when the record exists' do
|
||||||
it 'returns the todo' do
|
it 'returns the todo' do
|
||||||
|
|
@ -53,10 +56,13 @@ RSpec.describe 'Todos API', type: :request do
|
||||||
# Test suite for POST /todos
|
# Test suite for POST /todos
|
||||||
describe 'POST /todos' do
|
describe 'POST /todos' do
|
||||||
# valid payload
|
# 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
|
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
|
it 'creates a todo' do
|
||||||
expect(json['title']).to eq('Learn Elm')
|
expect(json['title']).to eq('Learn Elm')
|
||||||
|
|
@ -68,25 +74,26 @@ RSpec.describe 'Todos API', type: :request do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the request is invalid' do
|
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
|
it 'returns status code 422' do
|
||||||
expect(response).to have_http_status(422)
|
expect(response).to have_http_status(422)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a validation failure message' do
|
it 'returns a validation failure message' do
|
||||||
expect(response.body)
|
expect(json['message'])
|
||||||
.to match(/Validation failed: Created by can't be blank/)
|
.to match(/Validation failed: Title can't be blank/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Test suite for PUT /todos/:id
|
# Test suite for PUT /todos/:id
|
||||||
describe 'PUT /todos/:id' do
|
describe 'PUT /todos/:id' do
|
||||||
let(:valid_attributes) { { title: 'Shopping' } }
|
let(:valid_attributes) { { title: 'Shopping' }.to_json }
|
||||||
|
|
||||||
context 'when the record exists' do
|
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
|
it 'updates the record' do
|
||||||
expect(response.body).to be_empty
|
expect(response.body).to be_empty
|
||||||
|
|
@ -100,7 +107,7 @@ RSpec.describe 'Todos API', type: :request do
|
||||||
|
|
||||||
# Test suite for DELETE /todos/:id
|
# Test suite for DELETE /todos/:id
|
||||||
describe 'DELETE /todos/:id' do
|
describe 'DELETE /todos/:id' do
|
||||||
before { delete "/todos/#{todo_id}" }
|
before { delete "/todos/#{todo_id}", params: {}, headers: headers }
|
||||||
|
|
||||||
it 'returns status code 204' do
|
it 'returns status code 204' do
|
||||||
expect(response).to have_http_status(204)
|
expect(response).to have_http_status(204)
|
||||||
|
|
|
||||||
41
spec/requests/users_spec.rb
Normal file
41
spec/requests/users_spec.rb
Normal 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
|
||||||
28
spec/support/controller_spec_helper.rb
Normal file
28
spec/support/controller_spec_helper.rb
Normal 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
|
||||||
Loading…
Add table
Reference in a new issue