Commit f2a528ee by John Doe

refactored controllers to simpler api

parent aec8cf1c
# frozen_string_literal: true
# Controller for Database Objects
class DbsController < ApplicationController
before_action :authenticate_user!
before_action :set_db, only: [:show, :update]
before_action :authorize_viewer, only: [:show]
before_action :authorize_owner, only: [:update]
# GET /dbs.json
def show; end
# PATCH/PUT /dbs/1.json
def update
@service = StubService.new
if @db.update_attributes(db_params)
@service.add_notice('Database updated')
render status: :ok
else
@service.errors = @db.errors.full_messages
render status: :unprocessable_entity
end
end
private
#def refresh
# adapter = DbAdapter.new(@db.url)
# service = UpdateDb.new(db: @db)
# service.run(adapter.dbinfo, adapter.schema)
#end
def db_params
params.permit(:max_points_per_plot)
end
def set_db
@db = Db.find(params[:id])
@nilm = @db.nilm
end
# authorization based on nilms
def authorize_owner
head :unauthorized unless current_user.owns_nilm?(@nilm)
end
def authorize_viewer
head :unauthorized unless current_user.views_nilm?(@nilm)
end
end
require 'uri'
class JouleModulesController < ApplicationController
before_action :authenticate_user!, only: [:show]
before_action :authorize_viewer, only: [:show]
# GET /joule_modules/<nilm_id>.json
def show
if(params[:refresh])
adapter = JouleAdapter.new(@nilm.url)
@service = UpdateJouleModules.new(@nilm)
@service.run(adapter.module_info)
else
@service = StubService.new
end
@joule_modules = @nilm.joule_modules
# create the unique URL for module proxy traffic
@url_template = "http://%s.modules.wattsworth.local"
render status: @service.success? ? :ok : :unprocessable_entity
end
private
def authorize_viewer
@nilm = Nilm.find(params[:id])
head :unauthorized unless current_user.views_nilm?(@nilm)
end
end
......@@ -3,16 +3,30 @@
# controller for NILM objects
class NilmsController < ApplicationController
before_action :authenticate_user!
before_action :set_nilm, only: [:update, :refresh, :destroy]
before_action :set_nilm, only: [:update, :show, :refresh, :destroy]
before_action :authorize_viewer, only: [:show]
before_action :authorize_owner, only: [:update, :refresh]
before_action :authorize_admin, only: [:destroy]
# GET /nilms.json
def index
#just the NILM info, no database or joule modules
@nilms = current_user.retrieve_nilms_by_permission
end
def show
#render the database and joule modules
@role = current_user.get_nilm_permission(@nilm)
@url_template = "http://%s.modules.wattsworth.local"
#request new information from the NILM
if(params[:refresh])
@service = UpdateNilm.new()
@service.run(@nilm)
render status: @service.success? ? :ok : :unprocessable_entity
else
@service = StubService.new
end
end
# POST /nilms.json
def create
......@@ -22,27 +36,28 @@ class NilmsController < ApplicationController
description: nilm_params[:description],
owner: current_user)
@nilm = @service.nilm
@role = 'owner'
render :show, status: @service.success? ? :ok : :unprocessable_entity
end
# PATCH/PUT /nilms/1
# PATCH/PUT /nilms/1.json
def update
#update both the NILM and the Db models
@service = StubService.new
if @nilm.update(nilm_params)
if @nilm.update(nilm_params) && @db.update(db_params)
@service.add_notice('Installation Updated')
render :show, status: :ok
else
@service.errors = @nilm.errors.full_messages
@service.errors = @nilm.errors.full_messages +
@db.errors.full_messages
render :show, status: :unprocessable_entity
end
end
# PATCH/PUT /nilms/1/refresh.json
def refresh
@service = UpdateNilm.new()
@service.run(@nilm)
render status: @service.success? ? :ok : :unprocessable_entity
end
# DELETE /nilms/1.json
......@@ -57,13 +72,23 @@ class NilmsController < ApplicationController
# Use callbacks to share common setup or constraints between actions.
def set_nilm
@nilm = Nilm.find(params[:id])
@db = @nilm.db
end
# Never trust parameters from the scary internet, only allow the white list through.
# Never trust parameters from the scary internet,
# only allow the white list through.
def nilm_params
params.permit(:name, :description,:url)
end
def db_params
unless params[:db].nil?
params[:db].permit(:max_points_per_plot)
else
return {}
end
end
#authorization based on nilms
def authorize_admin
head :unauthorized unless current_user.admins_nilm?(@nilm)
......
......@@ -79,12 +79,18 @@ class User < ActiveRecord::Base
return self.has_permission(["admin","owner"],nilm)
end
#returns true if the user has <em> at least</em> +viewer+ privileges either directly or through a group
def views_nilm?(nilm)
return self.has_permission(["admin","owner","viewer"],nilm)
end
def get_nilm_permission(nilm)
return 'admin' if admins_nilm?(nilm)
return 'owner' if owns_nilm?(nilm)
return 'viewer' if views_nilm?(nilm)
return 'none'
end
def name
if self.first_name.nil? && self.last_name.nil?
if self.email.nil?
......
......@@ -9,10 +9,15 @@ class UpdateNilm
add_error('no associated db object')
return self
end
adapter = DbAdapter.new(nilm.url)
service = UpdateDb.new(db: nilm.db)
db_adapter = DbAdapter.new(nilm.url)
db_service = UpdateDb.new(db: nilm.db)
absorb_status(
service.run(adapter.dbinfo, adapter.schema)
db_service.run(db_adapter.dbinfo, db_adapter.schema)
)
joule_adapter = JouleAdapter.new(nilm.url)
joule_module_service = UpdateJouleModules.new(nilm)
absorb_status(
joule_module_service.run(joule_adapter.module_info)
)
self
end
......
json.extract! db, *Db.json_keys
json.db do
json.extract! db, *Db.json_keys
if(db.root_folder != nil)
json.contents do
root = db.root_folder
json.extract! root, *DbFolder.json_keys
if(db.root_folder != nil)
json.contents do
root = db.root_folder
json.extract! root, *DbFolder.json_keys
json.subfolders(root.subfolders) do |folder|
json.extract! folder, *DbFolder.json_keys
end
json.subfolders(root.subfolders) do |folder|
json.extract! folder, *DbFolder.json_keys
end
json.streams(root.db_streams) do |stream|
json.extract! stream, *DbStream.json_keys
json.elements(stream.db_elements) do |element|
json.extract! element, *DbElement.json_keys
json.streams(root.db_streams) do |stream|
json.extract! stream, *DbStream.json_keys
json.elements(stream.db_elements) do |element|
json.extract! element, *DbElement.json_keys
end
end
end
end
......
@data = @nilms[:admin].map{|nilm| {nilm: nilm, role: 'admin'}} +
@nilms[:owner].map{|nilm| {nilm: nilm, role: 'owner'}} +
@nilms[:viewer].map{|nilm| {nilm: nilm, role: 'viewer'}}
# frozen_string_literal: true
json.admin @nilms[:admin] do |nilm|
json.extract! nilm, *Nilm.json_keys
json.db_id nilm.db.id
json.available nilm.db.available
end
json.owner @nilms[:owner] do |nilm|
json.extract! nilm, *Nilm.json_keys
json.db_id nilm.db.id
json.available nilm.db.available
end
json.viewer @nilms[:viewer] do |nilm|
json.extract! nilm, *Nilm.json_keys
json.db_id nilm.db.id
json.available nilm.db.available
json.array!(@data) do |d|
nilm = d[:nilm]; role=d[:role]
json.extract! nilm, *Nilm.json_keys
json.role role
json.available nilm.db.available
end
# frozen_string_literal: true
json.data do
json.extract! @nilm, *Nilm.json_keys
json.role @role
unless @nilm.db.nil?
json.db_id @nilm.db.id
json.partial! "db", db: @nilm.db, as: :db
json.available @nilm.db.available
end
json.joule_modules(@nilm.joule_modules) do |m|
json.extract! m, *JouleModule.json_keys
json.url @url_template % [m.id]
json.nilm_id @nilm.id
end
end
json.partial! 'helpers/messages', service: @service
Rails.application.routes.draw do
resources :nilms, only: [:index, :create, :update, :destroy] do
resources :nilms, only: [:index, :show, :create, :update, :destroy] do
member do
put 'refresh'
end
......@@ -10,8 +10,7 @@ Rails.application.routes.draw do
get 'home' #retrieve a user's home data view
end
end
resources :joule_modules, only: [:show]
resources :dbs, only: [:show, :update]
resources :db_folders, only: [:show, :update]
resources :db_streams, only: [:index, :update] do
member do
......
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe DbsController, type: :request do
let(:john) { create(:user, first_name: 'John') }
let(:steve) { create(:user, first_name: 'Steve') }
let(:john_nilm) { create(:nilm, name: "John's NILM", admins: [john]) }
let(:lab_nilm) { create(:nilm, name: 'Lab NILM', owners: [john]) }
let(:pete_nilm) { create(:nilm, name: "Pete's NILM", viewers: [john])}
let(:hidden_nilm) { create(:nilm, name: "Private NILM", owners: [steve])}
# index action does not exist
describe 'GET show' do
context 'with any permissions' do
it 'returns the db as json' do
# john has some permission on all 3 nilms
@auth_headers = john.create_new_auth_token
[pete_nilm.db, lab_nilm.db, john_nilm.db].each do |db|
get "/dbs/#{db.id}.json",
headers: @auth_headers
expect(response.status).to eq(200)
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body['url']).to eq(db.url)
end
end
end
context 'without permissions' do
it 'returns unauthorized' do
# steve does NOT have permissions on john_nilm
@auth_headers = steve.create_new_auth_token
get "/dbs/#{john_nilm.db.id}.json",
headers: @auth_headers
expect(response.status).to eq(401)
end
end
context 'without sign-in' do
it 'returns unauthorized' do
# no headers: nobody is signed in, deny all
get "/dbs/#{john_nilm.db.id}.json"
expect(response.status).to eq(401)
end
end
end
describe 'PUT update' do
context 'with owner permissions' do
it 'returns 422 on invalid parameters' do
# max points must be a positive number
@auth_headers = john.create_new_auth_token
put "/dbs/#{john_nilm.db.id}.json",
params: {max_points_per_plot: 'invalid'},
headers: @auth_headers
expect(response.status).to eq(422)
expect(response).to have_error_message(/not a number/)
end
it 'only allows configurable parameters to be changed' do
# should ignore size and accept max_points
@auth_headers = john.create_new_auth_token
url = john_nilm.db.url
num_points = john_nilm.db.max_points_per_plot
put "/dbs/#{john_nilm.db.id}.json",
params: {max_points_per_plot: num_points+10, url: 'different'},
headers: @auth_headers
expect(response.status).to eq(200)
expect(response).to have_notice_message()
expect(john_nilm.db.reload.url).to eq(url)
expect(john_nilm.db.max_points_per_plot).to eq(num_points+10)
end
end
context 'without owner permissions' do
it 'returns unauthorized' do
@auth_headers = john.create_new_auth_token
num_points = pete_nilm.db.max_points_per_plot
put "/dbs/#{pete_nilm.db.id}.json",
params: {max_points_per_plot: num_points+10},
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
expect(pete_nilm.db.max_points_per_plot).to eq(num_points)
end
end
context 'without sign-in' do
it 'returns unauthorized' do
num_points = pete_nilm.db.max_points_per_plot
put "/dbs/#{pete_nilm.db.id}.json",
params: {max_points_per_plot: num_points+10}
expect(response).to have_http_status(:unauthorized)
expect(pete_nilm.db.max_points_per_plot).to eq(num_points)
end
end
end
end
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe JouleModulesController, type: :request do
let(:john) { create(:user, first_name: 'John') }
let(:steve) { create(:user, first_name: 'Steve') }
let(:john_nilm) { create(:nilm, name: "John's NILM", admins: [john]) }
let(:lab_nilm) { create(:nilm, name: 'Lab NILM', owners: [john]) }
let(:pete_nilm) { create(:nilm, name: "Pete's NILM", viewers: [john])}
# index action does not exist
describe 'GET show' do
context 'with any permissions' do
it 'returns the modules as json' do
# john has some permission on all 3 nilms
@auth_headers = john.create_new_auth_token
[pete_nilm, lab_nilm, john_nilm].each do |nilm|
get "/joule_modules/#{nilm.id}.json",
headers: @auth_headers
expect(response.status).to eq(200)
expect(response.header['Content-Type']).to include('application/json')
end
end
it 'refreshes modules when requested' do
@mock_adapter = double(JouleAdapter)
allow(JouleAdapter).to receive(:new).and_return(@mock_adapter)
expect(@mock_adapter).to receive(:module_info).and_return([])
@auth_headers = john.create_new_auth_token
get "/joule_modules/#{john_nilm.id}.json?refresh=1",
headers: @auth_headers
expect(response.status).to eq(200)
expect(response.header['Content-Type']).to include('application/json')
end
it 'injects the proxy URL parameter into the module json' do
test_module = create(:joule_module, name: 'test', description: 'sample')
john_nilm.joule_modules << test_module
get "/joule_modules/#{john_nilm.id}.json",
headers: john.create_new_auth_token
body = JSON.parse(response.body)
expect(body['data'][0]['name']).to eq(test_module.name)
expect(body['data'][0]['url']).to start_with("http://#{test_module.id}.modules")
end
end
context 'without permissions' do
it 'returns unauthorized' do
# steve does NOT have permissions on john_nilm
@auth_headers = steve.create_new_auth_token
get "/joule_modules/#{john_nilm.id}.json",
headers: @auth_headers
expect(response.status).to eq(401)
end
end
context 'without sign-in' do
it 'returns unauthorized' do
# no headers: nobody is signed in, deny all
get "/joule_modules/#{john_nilm.id}.json"
expect(response.status).to eq(401)
end
end
end
end
......@@ -20,9 +20,18 @@ RSpec.describe NilmsController, type: :request do
get "/nilms.json", headers: @auth_headers
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body["admin"][0]["id"]).to eq(john_nilm.id)
expect(body["owner"][0]["id"]).to eq(lab_nilm.id)
expect(body["viewer"][0]["id"]).to eq(pete_nilm.id)
expect(body.length).to eq 3
body.each do |nilm|
if(nilm['id']==john_nilm.id)
expect(nilm["role"]).to eq("admin")
elsif(nilm['id']==lab_nilm.id)
expect(nilm["role"]).to eq("owner")
elsif(nilm['id']==pete_nilm.id)
expect(nilm["role"]).to eq("viewer")
else
fail "unexpected nilm in json response"
end
end
end
end
context 'without sign-in' do
......@@ -46,7 +55,7 @@ RSpec.describe NilmsController, type: :request do
expect(nilm.reload.name).to eq("changed:#{nilm.id}")
end
end
it 'returns 422 on invalid parameters' do
it 'returns 422 on invalid nilm parameters' do
@auth_headers = john.create_new_auth_token
put "/nilms/#{john_nilm.id}.json",
params: {id: john_nilm.id, name: ""},
......@@ -55,57 +64,106 @@ RSpec.describe NilmsController, type: :request do
expect(response).to have_error_message(/Name/)
expect(john_nilm.reload.name).to eq("John's NILM")
end
it 'returns 422 on invalid db parameters' do
# max points must be a positive number
put "/nilms/#{john_nilm.id}.json",
params: {db: {max_points_per_plot: 'invalid'}},
headers: john.create_new_auth_token
expect(response.status).to eq(422)
expect(response).to have_error_message(/not a number/)
end
it 'only allows configurable db parameters to be changed' do
# should ignore size and accept max_points
url = john_nilm.db.url
num_points = john_nilm.db.max_points_per_plot
put "/nilms/#{john_nilm.id}.json",
params: {db: {max_points_per_plot: num_points+10, url: 'different'}},
headers: john.create_new_auth_token
expect(response.status).to eq(200)
expect(response).to have_notice_message()
expect(john_nilm.db.reload.url).to eq(url)
expect(john_nilm.db.max_points_per_plot).to eq(num_points+10)
end
end
context 'without admin permissions' do
it 'returns unauthorized' do
@auth_headers = john.create_new_auth_token
num_points = pete_nilm.db.max_points_per_plot
put "/nilms/#{pete_nilm.id}.json",
params: {id: pete_nilm.id, name: "test"},
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
expect(pete_nilm.reload.name).to eq("Pete's NILM")
expect(pete_nilm.db.max_points_per_plot).to eq(num_points)
end
end
context 'without sign-in' do
it 'returns unauthorized' do
num_points = pete_nilm.db.max_points_per_plot
put "/nilms/#{pete_nilm.id}.json",
params: {id: pete_nilm.id, name: "test"}
expect(response).to have_http_status(:unauthorized)
expect(pete_nilm.reload.name).to eq("Pete's NILM")
expect(pete_nilm.db.max_points_per_plot).to eq(num_points)
end
end
end
describe 'PUT refresh' do
context 'with owner or admin' do
it 'updates the db' do
describe 'GET show' do
context 'with any permissions' do
it 'returns nilm and nested db as json' do
# john has some permission on all 3 nilms
[pete_nilm, lab_nilm, john_nilm].each do |nilm|
get "/nilms/#{nilm.id}.json",
headers: john.create_new_auth_token
expect(response.status).to eq(200)
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body['data']['name']).to eq(nilm.name)
expect(body['data']['db']['url']).to eq(nilm.db.url)
end
end
it 'returns joule modules as json' do
test_module = create(:joule_module, name: 'test', description: 'sample')
john_nilm.joule_modules << test_module
get "/nilms/#{john_nilm.id}.json",
headers: john.create_new_auth_token
body = JSON.parse(response.body)
expect(body['data']['joule_modules'][0]['name']).to eq(test_module.name)
expect(body['data']['joule_modules'][0]['url']).to start_with("http://#{test_module.id}.modules")
end
it 'refreshes nilm data when requested' do
@auth_headers = john.create_new_auth_token
[john_nilm, lab_nilm].each do |nilm|
mock_service = UpdateNilm.new
expect(mock_service).to receive(:run).and_return StubService.new
allow(UpdateNilm).to receive(:new)
.and_return(mock_service)
put "/nilms/#{nilm.id}/refresh.json",
get "/nilms/#{nilm.id}.json?refresh=1",
headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(response.header['Content-Type']).to include('application/json')
end
end
end
context 'with anyone else' do
it 'returns unauthorized' do
@auth_headers = steve.create_new_auth_token
put "/nilms/#{john_nilm.id}/refresh.json",
get "/nilms/#{john_nilm.id}.json",
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
end
end
context 'without sign-in' do
it 'returns unauthorized' do
put "/nilms/#{pete_nilm.id}/refresh.json"
put "/nilms/#{pete_nilm.id}.json?refresh=1"
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'POST create' do
context 'with authenticated user' do
it 'creates a NILM' do
......
......@@ -34,6 +34,11 @@ RSpec.describe User, type: :model do
@lab = create(:nilm, name: "LEES Lab", admins: [@john, @leeb],
owners: [@labmates], viewers: [@public])
end
it "associates nilms with permissions" do
expect(@john.get_nilm_permission(@donnal_house)).to eq('admin')
expect(@pete.get_nilm_permission(@lab)).to eq('owner')
expect(@nicky.get_nilm_permission(@lab)).to eq('viewer')
end
it "lets John admin his house and the lab" do
expect(@john.admins_nilm?(@donnal_house)).to eq(true)
expect(@john.owns_nilm?(@donnal_house)).to eq(true)
......
......@@ -10,7 +10,9 @@ describe 'UpdateNilm' do
warnings: [])
allow(UpdateDb).to receive(:new)
.and_return(mock_service)
mock_adapter = double(JouleAdapter)
allow(JouleAdapter).to receive(:new).and_return(mock_adapter)
expect(mock_adapter).to receive(:module_info).and_return([])
nilm = create(:nilm)
service = UpdateNilm.new()
service.run(nilm)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment