diff --git a/.gitignore b/.gitignore
index 5b80ff5..f732b7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,4 +25,4 @@
# Ignore master key for decrypting credentials and more.
/config/master.key
-/.env
\ No newline at end of file
+.env
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
index d49723c..c9d6552 100644
--- a/Gemfile
+++ b/Gemfile
@@ -41,4 +41,10 @@ end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
-gem 'dotenv-rails'
\ No newline at end of file
+gem 'dotenv-rails'
+
+gem 'faraday', '~> 0.11'
+
+gem 'jwt', '~> 1.5'
+
+gem 'pry'
\ No newline at end of file
diff --git a/Gemfile.lock b/Gemfile.lock
index cb1b28d..2634f98 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -60,6 +60,7 @@ GEM
msgpack (~> 1.0)
builder (3.2.3)
byebug (11.0.1)
+ coderay (1.1.2)
concurrent-ruby (1.1.5)
crass (1.0.4)
dotenv (2.7.5)
@@ -67,11 +68,14 @@ GEM
dotenv (= 2.7.5)
railties (>= 3.2, < 6.1)
erubi (1.8.0)
+ faraday (0.15.4)
+ multipart-post (>= 1.2, < 3)
ffi (1.11.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
+ jwt (1.5.6)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
@@ -89,9 +93,13 @@ GEM
mini_portile2 (2.4.0)
minitest (5.11.3)
msgpack (1.3.1)
+ multipart-post (2.1.1)
nio4r (2.5.1)
nokogiri (1.10.4)
mini_portile2 (~> 2.4.0)
+ pry (0.12.2)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
puma (3.12.1)
rack (2.0.7)
rack-test (1.1.0)
@@ -155,7 +163,10 @@ DEPENDENCIES
bootsnap (>= 1.4.2)
byebug
dotenv-rails
+ faraday (~> 0.11)
+ jwt (~> 1.5)
listen (>= 3.0.5, < 3.2)
+ pry
puma (~> 3.11)
rails (~> 6.0.0)
spring
diff --git a/Rakefile b/Rakefile
index fb4148c..f0e29a5 100644
--- a/Rakefile
+++ b/Rakefile
@@ -3,6 +3,8 @@
require_relative 'config/application'
require 'fileutils'
+require 'dotenv'
+
namespace :start do
task :development do
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 4ac8823..f6f3667 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,2 +1,16 @@
class ApplicationController < ActionController::API
-end
+ def current_user
+ token = params[:token]
+ payload = TokenEncoder.decode(token)
+ puts payload
+ @current_user ||= User.find_by_login(payload[0]['sub'])
+ end
+
+ def logged_in?
+ current_user != nil
+ end
+
+ def authenticate_user!
+ head :unauthorized unless logged_in?
+ end
+ end
\ No newline at end of file
diff --git a/app/controllers/authentication_controller.rb b/app/controllers/authentication_controller.rb
new file mode 100644
index 0000000..9beacd3
--- /dev/null
+++ b/app/controllers/authentication_controller.rb
@@ -0,0 +1,35 @@
+
+require 'pry'
+
+class AuthenticationController < ApplicationController
+ def github
+
+ #binding.pry
+
+ authenticator = Authenticator.new
+ user_info = authenticator.github(params[:code])
+
+ login = user_info[:login]
+ name = user_info[:name]
+ puts login
+
+ # Generate token...
+ token = TokenEncoder.encode(login)
+ # ... create user if it doesn't exist...
+ User.where(login: login).first_or_create!(
+ name: name,
+ #avatar_url: avatar_url
+ )
+ puts "here: "+token
+ # ... and redirect to client app.
+ redirect_to "#{issuer}?token=#{token}"
+ rescue StandardError => error
+ redirect_to "#{issuer}?error=#{error.message}"
+ end
+
+ private
+
+ def issuer
+ ENV['CLIENT_URL']
+ end
+ end
\ No newline at end of file
diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb
new file mode 100644
index 0000000..0c523c2
--- /dev/null
+++ b/app/controllers/dashboards_controller.rb
@@ -0,0 +1,52 @@
+class DashboardsController < ApplicationController
+ before_action :authenticate_user!
+ before_action :set_dashboard, only: [:show, :update, :destroy]
+
+ # GET /dashboards
+ def index
+ @dashboards = Dashboard.all
+
+ render json: @dashboards
+ end
+
+ # GET /dashboards/1
+ def show
+ render json: @dashboard
+ end
+
+ # POST /dashboards
+ def create
+ @dashboard = Dashboard.new(dashboard_params)
+
+ if @dashboard.save
+ render json: @dashboard, status: :created, location: @dashboard
+ else
+ render json: @dashboard.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PATCH/PUT /dashboards/1
+ def update
+ if @dashboard.update(dashboard_params)
+ render json: @dashboard
+ else
+ render json: @dashboard.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /dashboards/1
+ def destroy
+ @dashboard.destroy
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_dashboard
+ @dashboard = Dashboard.find(params[:id])
+ end
+
+ # Only allow a trusted parameter "white list" through.
+ def dashboard_params
+ params.require(:dashboard).permit(:user_id)
+ end
+end
diff --git a/app/controllers/test_controller.rb b/app/controllers/test_controller.rb
index 122e420..fb9fdc7 100644
--- a/app/controllers/test_controller.rb
+++ b/app/controllers/test_controller.rb
@@ -1,7 +1,8 @@
class TestController < ApplicationController
+ before_action :authenticate_user!
def new
- foo = {foo:"bar"}
+ foo = {foo:current_user}
render :json => foo
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
new file mode 100644
index 0000000..82adb9c
--- /dev/null
+++ b/app/controllers/users_controller.rb
@@ -0,0 +1,51 @@
+class UsersController < ApplicationController
+ before_action :set_user, only: [:show, :update, :destroy]
+
+ # GET /users
+ def index
+ @users = User.all
+
+ render json: @users
+ end
+
+ # GET /users/1
+ def show
+ render json: @user
+ end
+
+ # POST /users
+ def create
+ @user = User.new(user_params)
+
+ if @user.save
+ render json: @user, status: :created, location: @user
+ else
+ render json: @user.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PATCH/PUT /users/1
+ def update
+ if @user.update(user_params)
+ render json: @user
+ else
+ render json: @user.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /users/1
+ def destroy
+ @user.destroy
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_user
+ @user = User.find(params[:id])
+ end
+
+ # Only allow a trusted parameter "white list" through.
+ def user_params
+ params.require(:user).permit(:login, :name)
+ end
+end
diff --git a/app/models/dashboard.rb b/app/models/dashboard.rb
new file mode 100644
index 0000000..d8c4b22
--- /dev/null
+++ b/app/models/dashboard.rb
@@ -0,0 +1,3 @@
+class Dashboard < ApplicationRecord
+ belongs_to :user
+end
diff --git a/app/models/user.rb b/app/models/user.rb
new file mode 100644
index 0000000..379658a
--- /dev/null
+++ b/app/models/user.rb
@@ -0,0 +1,2 @@
+class User < ApplicationRecord
+end
diff --git a/client/src/App.js b/client/src/App.js
index 397b706..6d8ddbd 100644
--- a/client/src/App.js
+++ b/client/src/App.js
@@ -1,15 +1,22 @@
-import React from 'react';
-
+import React, { Component } from 'react';
+import { getQueryParams } from "./utility/urlUtility"
import './App.css';
-
-function App() {
+import Login from'./component/login'
+class App extends Component {
+
+ constructor(){
+ super()
+ this.state = { token: getQueryParams().token }
+ }
+ render(){
return (
- Yo!
+
+ {!this.state.token ? : "" }
- );
+ );}
}
export default App;
diff --git a/client/src/component/login/index.js b/client/src/component/login/index.js
new file mode 100644
index 0000000..e1a26ca
--- /dev/null
+++ b/client/src/component/login/index.js
@@ -0,0 +1,6 @@
+import React from 'react'
+
+
+export default ()=>{
+ return ( log in w/ github)
+}
\ No newline at end of file
diff --git a/client/src/index.js b/client/src/index.js
index 47a7de0..e27b6be 100644
--- a/client/src/index.js
+++ b/client/src/index.js
@@ -2,13 +2,13 @@ import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
-import { BrowserRouter as Router, Route } from 'react-router-dom';
+import { BrowserRouter, Route } from 'react-router-dom';
import * as serviceWorker from './serviceWorker';
-ReactDOM.render((
-
-
- ), document.getElementById('root'));
+ReactDOM.render(
+
+
+ , document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
diff --git a/client/src/utility/urlUtility.js b/client/src/utility/urlUtility.js
new file mode 100644
index 0000000..efc23d8
--- /dev/null
+++ b/client/src/utility/urlUtility.js
@@ -0,0 +1,8 @@
+export function getQueryParams() {
+ const query = window.location.search.substring(1);
+ const pairs = query.split('&').map((str) => str.split('='));
+ return pairs.reduce((memo, pair) => {
+ memo[pair[0]] = pair[1];
+ return memo;
+ }, {});
+ }
\ No newline at end of file
diff --git a/config/application.rb b/config/application.rb
index f9ba45c..60ac42a 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -19,11 +19,16 @@
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
+
+
module CustomDash
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.0
+ config.autoload_paths += %W(#{config.root}/lib)
+ config.autoload_paths += Dir["#{config.root}/lib/**/"]
+
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
diff --git a/config/routes.rb b/config/routes.rb
index 9e86edf..f728dcd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,5 +1,8 @@
Rails.application.routes.draw do
+ resources :dashboards
+ resources :users
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
get "/test" => "test#new"
- get "/auth/google/callback" => "session#googleAuth"
+ #get "/auth/google/callback" => "session#googleAuth"
+ get '/auth/github', to: 'authentication#github', format: false
end
diff --git a/db/migrate/20190831164054_create_users.rb b/db/migrate/20190831164054_create_users.rb
new file mode 100644
index 0000000..4f42ace
--- /dev/null
+++ b/db/migrate/20190831164054_create_users.rb
@@ -0,0 +1,10 @@
+class CreateUsers < ActiveRecord::Migration[6.0]
+ def change
+ create_table :users do |t|
+ t.string :login
+ t.string :name
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20190831165244_create_dashboards.rb b/db/migrate/20190831165244_create_dashboards.rb
new file mode 100644
index 0000000..b4523f8
--- /dev/null
+++ b/db/migrate/20190831165244_create_dashboards.rb
@@ -0,0 +1,9 @@
+class CreateDashboards < ActiveRecord::Migration[6.0]
+ def change
+ create_table :dashboards do |t|
+ t.references :user, null: false, foreign_key: true
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 0000000..ca8281c
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,30 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# This file is the source Rails uses to define your schema when running `rails
+# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema.define(version: 2019_08_31_165244) do
+
+ create_table "dashboards", force: :cascade do |t|
+ t.integer "user_id", null: false
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
+ t.index ["user_id"], name: "index_dashboards_on_user_id"
+ end
+
+ create_table "users", force: :cascade do |t|
+ t.string "login"
+ t.string "name"
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
+ end
+
+ add_foreign_key "dashboards", "users"
+end
diff --git a/lib/authenticator.rb b/lib/authenticator.rb
new file mode 100644
index 0000000..3189e11
--- /dev/null
+++ b/lib/authenticator.rb
@@ -0,0 +1,43 @@
+class Authenticator
+ def initialize(connection = Faraday.new)
+ @connection = connection
+ end
+
+ def github(code)
+ access_token_resp = fetch_github_access_token(code)
+ access_token = access_token_resp['access_token']
+ user_info_resp = fetch_github_user_info(access_token)
+ puts user_info_resp
+ {
+ issuer: ENV['CLIENT_URL'],
+ login: user_info_resp['login'],
+ name: user_info_resp['name'],
+ #avatar_url: user_info_resp['avatar_url']
+ }
+ end
+
+ private
+
+ def fetch_github_access_token(code)
+ resp = @connection.post ENV['GITHUB_ACCESS_TOKEN_URL'], {
+ code: code,
+ client_id: ENV['CLIENT_ID'],
+ client_secret: ENV['CLIENT_SECRET']
+ }
+ #binding.pry
+ raise IOError, 'FETCH_ACCESS_TOKEN' unless resp.success?
+ URI.decode_www_form(resp.body).to_h
+ end
+
+ def fetch_github_user_info(access_token)
+ #binding.pry
+ resp = @connection.get ENV['GITHUB_USER_INFO_URL'], {
+ access_token: access_token
+ }
+
+
+
+ raise IOError, 'FETCH_USER_INFO' unless resp.success?
+ JSON.parse(resp.body)
+ end
+ end
\ No newline at end of file
diff --git a/lib/token_encoder.rb b/lib/token_encoder.rb
new file mode 100644
index 0000000..5f41e7e
--- /dev/null
+++ b/lib/token_encoder.rb
@@ -0,0 +1,22 @@
+module TokenEncoder
+ def self.encode(sub)
+ payload = {
+ iss: ENV['CLIENT_URL'],
+ sub: sub,
+ exp: 4.hours.from_now.to_i,
+ iat: Time.now.to_i
+ }
+ JWT.encode payload, ENV['JWT_SECRET'], 'HS256'
+ end
+
+ def self.decode(token)
+ options = {
+ iss: ENV['CLIENT_URL'],
+ verify_iss: true,
+ verify_iat: true,
+ leeway: 30,
+ algorithm: 'HS256'
+ }
+ JWT.decode token, ENV['JWT_SECRET'], true, options
+ end
+ end
\ No newline at end of file
diff --git a/test/controllers/authentication_controller_test.rb b/test/controllers/authentication_controller_test.rb
new file mode 100644
index 0000000..ab5e221
--- /dev/null
+++ b/test/controllers/authentication_controller_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class AuthenticationControllerTest < ActionDispatch::IntegrationTest
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/controllers/dashboards_controller_test.rb b/test/controllers/dashboards_controller_test.rb
new file mode 100644
index 0000000..f8371eb
--- /dev/null
+++ b/test/controllers/dashboards_controller_test.rb
@@ -0,0 +1,38 @@
+require 'test_helper'
+
+class DashboardsControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ @dashboard = dashboards(:one)
+ end
+
+ test "should get index" do
+ get dashboards_url, as: :json
+ assert_response :success
+ end
+
+ test "should create dashboard" do
+ assert_difference('Dashboard.count') do
+ post dashboards_url, params: { dashboard: { user_id: @dashboard.user_id } }, as: :json
+ end
+
+ assert_response 201
+ end
+
+ test "should show dashboard" do
+ get dashboard_url(@dashboard), as: :json
+ assert_response :success
+ end
+
+ test "should update dashboard" do
+ patch dashboard_url(@dashboard), params: { dashboard: { user_id: @dashboard.user_id } }, as: :json
+ assert_response 200
+ end
+
+ test "should destroy dashboard" do
+ assert_difference('Dashboard.count', -1) do
+ delete dashboard_url(@dashboard), as: :json
+ end
+
+ assert_response 204
+ end
+end
diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb
new file mode 100644
index 0000000..2a2e246
--- /dev/null
+++ b/test/controllers/users_controller_test.rb
@@ -0,0 +1,38 @@
+require 'test_helper'
+
+class UsersControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ @user = users(:one)
+ end
+
+ test "should get index" do
+ get users_url, as: :json
+ assert_response :success
+ end
+
+ test "should create user" do
+ assert_difference('User.count') do
+ post users_url, params: { user: { login: @user.login, name: @user.name } }, as: :json
+ end
+
+ assert_response 201
+ end
+
+ test "should show user" do
+ get user_url(@user), as: :json
+ assert_response :success
+ end
+
+ test "should update user" do
+ patch user_url(@user), params: { user: { login: @user.login, name: @user.name } }, as: :json
+ assert_response 200
+ end
+
+ test "should destroy user" do
+ assert_difference('User.count', -1) do
+ delete user_url(@user), as: :json
+ end
+
+ assert_response 204
+ end
+end
diff --git a/test/fixtures/dashboards.yml b/test/fixtures/dashboards.yml
new file mode 100644
index 0000000..6dc1ab3
--- /dev/null
+++ b/test/fixtures/dashboards.yml
@@ -0,0 +1,7 @@
+# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+one:
+ user: one
+
+two:
+ user: two
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
new file mode 100644
index 0000000..3b34319
--- /dev/null
+++ b/test/fixtures/users.yml
@@ -0,0 +1,9 @@
+# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+one:
+ login: MyString
+ name: MyString
+
+two:
+ login: MyString
+ name: MyString
diff --git a/test/models/dashboard_test.rb b/test/models/dashboard_test.rb
new file mode 100644
index 0000000..48d77a9
--- /dev/null
+++ b/test/models/dashboard_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class DashboardTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/models/user_test.rb b/test/models/user_test.rb
new file mode 100644
index 0000000..82f61e0
--- /dev/null
+++ b/test/models/user_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class UserTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end