Commit 4cff7d2e by John Doe

added tests for data view creation and retrieval

parent 9923f914
class DataViewsController < ApplicationController
before_action :authenticate_user!
before_action :set_data_view, only: [:update, :destroy]
before_action :authorize_owner, only: [:update, :destroy]
def index
@data_views = DataView.find_viewable(current_user)
end
# POST /data_views.json
def create
@service = CreateDataView.new()
@service.run(data_view_params, params[:stream_ids], current_user)
@data_view = @service.data_view
render :show, status: @service.success? ? :ok : :unprocessable_entity
end
# PATCH/PUT /data_views/1.json
def update
@service = StubService.new
if @data_view.update(updatable_data_view_params)
@service.add_notice('updated data view')
render :show, status: :ok
else
@service.errors = @data_view.errors.full_messages
render :show, status: :unprocessable_entity
end
end
# DELETE /data_views/1.json
def destroy
@service = StubService.new
@data_view.destroy
@service.set_notice('removed data view')
end
private
def data_view_params
params.permit(:name, :description, :image, :redux_json)
end
def updatable_data_view_params
params.permit(:name, :description)
end
def set_data_view
@data_view = DataView.find(params[:id])
end
def authorize_owner
head :unauthorized unless @data_view.owner == current_user
end
end
class DataView < ApplicationRecord
#---Associations----
has_many :data_views_nilms
has_many :nilms, through: :data_views_nilms, dependent: :destroy
belongs_to :owner,
class_name: 'User',
foreign_key: 'user_id'
#---Validations-----
validates :name, :presence => true
#return all DataViews that can be loaded by this user
def self.find_viewable(user)
#make a list of allowed nilms
r = user.retrieve_nilms_by_permission
nilms = r[:admin]+r[:owner]+r[:viewer]
#find all DataViewsNilms that are not allowed
prohibited = DataViewsNilm.where.not(nilm_id: nilms.pluck(:id))
#find the *other* DataViewsNilms (allowed)
allowed_ids = DataViewsNilm.where.not(id: prohibited.pluck(:id))
.pluck(:data_view_id).uniq
DataView.find(allowed_ids)
end
def self.json_keys
[:id, :name, :description, :image, :redux_json]
end
end
class DataViewsNilm < ApplicationRecord
belongs_to :nilm
belongs_to :data_view
end
...@@ -28,9 +28,9 @@ class DbElement < ApplicationRecord ...@@ -28,9 +28,9 @@ class DbElement < ApplicationRecord
self.display_type = 'continuous' self.display_type = 'continuous'
end end
def name_path # def name_path
"#{db_stream.name_path}/#{self.name}" # "#{db_stream.name_path}/#{self.name}"
end # end
def self.json_keys def self.json_keys
[:id, :db_stream_id, :name, :units, :column, :default_max, [:id, :db_stream_id, :name, :units, :column, :default_max,
......
...@@ -27,10 +27,10 @@ class DbFolder < ApplicationRecord ...@@ -27,10 +27,10 @@ class DbFolder < ApplicationRecord
self.parent == nil self.parent == nil
end end
def name_path # def name_path
return "" if root_folder? # return "" if root_folder?
return "#{parent.name_path}/#{self.name}" # return "#{parent.name_path}/#{self.name}"
end # end
def self.defined_attributes def self.defined_attributes
[:name, :description, :hidden] [:name, :description, :hidden]
......
...@@ -32,9 +32,9 @@ class DbStream < ApplicationRecord ...@@ -32,9 +32,9 @@ class DbStream < ApplicationRecord
[:name, :name_abbrev, :description, :hidden] [:name, :name_abbrev, :description, :hidden]
end end
def name_path # def name_path
"#{db_folder.name_path}/#{self.name}" # "#{db_folder.name_path}/#{self.name}"
end # end
def remove(db_service:) def remove(db_service:)
db_service.remove_file(path) db_service.remove_file(path)
......
...@@ -8,11 +8,18 @@ class Nilm < ApplicationRecord ...@@ -8,11 +8,18 @@ class Nilm < ApplicationRecord
has_many :permissions, dependent: :destroy #viewer, owner, admin has_many :permissions, dependent: :destroy #viewer, owner, admin
has_many :users, through: :permissions has_many :users, through: :permissions
has_many :user_groups, through: :permissions has_many :user_groups, through: :permissions
has_many :data_views_nilms
has_many :data_views, through: :data_views_nilms
#---Validations----- #---Validations-----
validates :name, presence: true, uniqueness: true validates :name, presence: true, uniqueness: true
validates :url, presence: true, uniqueness: true validates :url, presence: true, uniqueness: true
#---Callbacks------
before_destroy do |record|
DataView.destroy(record.data_views.pluck(:id))
end
def self.json_keys def self.json_keys
[:id, :name, :description, :url] [:id, :name, :description, :url]
end end
......
...@@ -10,6 +10,7 @@ class User < ActiveRecord::Base ...@@ -10,6 +10,7 @@ class User < ActiveRecord::Base
has_many :nilms, through: :permissions has_many :nilms, through: :permissions
has_many :memberships has_many :memberships
has_many :user_groups, through: :memberships has_many :user_groups, through: :memberships
has_many :data_views
#---Validations----- #---Validations-----
validates :first_name, :last_name, :email, :presence => true validates :first_name, :last_name, :email, :presence => true
......
...@@ -62,7 +62,7 @@ class LoadElementData ...@@ -62,7 +62,7 @@ class LoadElementData
if data_service.success? if data_service.success?
combined_data.concat(data_service.data) combined_data.concat(data_service.data)
else else
add_warning("unable to retrieve data for #{stream.name_path}") add_warning("unable to retrieve data for #{stream.path}")
end end
end end
#3 extract requested elements from the stream datasets #3 extract requested elements from the stream datasets
......
# frozen_string_literal: true
# Create a Data View
class CreateDataView
include ServiceStatus
attr_reader :data_view
def run(data_view_params, stream_ids, user)
#retrieve nilms for every stream
begin
db_ids = DbStream
.find(stream_ids)
.pluck(:db_id)
.uniq
nilm_ids = Db
.find(db_ids)
.pluck(:nilm_id)
rescue ActiveRecord::RecordNotFound
self.add_errors(['invalid stream_ids'])
return self
end
@data_view = DataView.create(data_view_params)
@data_view.nilm_ids = nilm_ids
@data_view.owner = user
unless @data_view.save
self.add_errors(@data_view.errors.full_messages)
return self
end
self.set_notice('created data view')
self
end
end
json.array! @data_views do |view|
json.extract! view, *DataView.json_keys
json.owner current_user==view.owner
end
json.data do
json.extract! @data_view, *DataView.json_keys
json.owner current_user==@data_view.owner
end
json.partial! "helpers/messages", service: @service
json.array! @elements do |element| json.array! @elements do |element|
json.extract! element, *DbElement.json_keys json.extract! element, *DbElement.json_keys
json.path element.name_path
end end
...@@ -13,7 +13,7 @@ module ControlPanel ...@@ -13,7 +13,7 @@ module ControlPanel
# -- all .rb files in that directory are automatically loaded. # -- all .rb files in that directory are automatically loaded.
config.api_only = true config.api_only = true
# Add folders under the services and adapters directory # Add folders under the services and adapters directory
%w(data nilm db db_folder db_stream permission user_group user).each do |service| %w(data nilm db db_folder db_stream permission user_group user data_view).each do |service|
config.autoload_paths << Rails.root.join("app/services/#{service}") config.autoload_paths << Rails.root.join("app/services/#{service}")
end end
config.autoload_paths << Rails.root.join("app/adapters") config.autoload_paths << Rails.root.join("app/adapters")
......
...@@ -5,6 +5,7 @@ Rails.application.routes.draw do ...@@ -5,6 +5,7 @@ Rails.application.routes.draw do
put 'refresh' put 'refresh'
end end
end end
resources :data_views
resources :dbs, only: [:show, :update] resources :dbs, only: [:show, :update]
resources :db_folders, only: [:show, :update] resources :db_folders, only: [:show, :update]
resources :db_streams, only: [:update] resources :db_streams, only: [:update]
......
class CreateDataViews < ActiveRecord::Migration[5.0]
def change
create_table :data_views do |t|
t.integer :user_id
t.string :name
t.string :description
t.text :image
t.text :redux_json
t.timestamps
end
create_table :data_views_nilms, id: false do |t|
t.integer :data_view_id
t.integer :nilm_id
end
add_index :data_views_nilms, :nilm_id
add_index :data_views_nilms, :data_view_id
end
end
class AddPrimaryKeysToJoinTables < ActiveRecord::Migration[5.0]
def change
add_column :data_views_nilms, :id, :primary_key
add_column :memberships, :id, :primary_key
end
end
...@@ -10,7 +10,24 @@ ...@@ -10,7 +10,24 @@
# #
# 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: 20170506014329) do ActiveRecord::Schema.define(version: 20170512013633) do
create_table "data_views", force: :cascade do |t|
t.integer "user_id"
t.string "name"
t.string "description"
t.text "image"
t.text "redux_json"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "data_views_nilms", force: :cascade do |t|
t.integer "data_view_id"
t.integer "nilm_id"
t.index ["data_view_id"], name: "index_data_views_nilms_on_data_view_id"
t.index ["nilm_id"], name: "index_data_views_nilms_on_nilm_id"
end
create_table "db_decimations", force: :cascade do |t| create_table "db_decimations", force: :cascade do |t|
t.integer "start_time", limit: 8 t.integer "start_time", limit: 8
...@@ -86,7 +103,7 @@ ActiveRecord::Schema.define(version: 20170506014329) do ...@@ -86,7 +103,7 @@ ActiveRecord::Schema.define(version: 20170506014329) do
t.boolean "available" t.boolean "available"
end end
create_table "memberships", id: false, force: :cascade do |t| create_table "memberships", force: :cascade do |t|
t.integer "user_group_id" t.integer "user_group_id"
t.integer "user_id" t.integer "user_id"
t.index ["user_group_id"], name: "index_memberships_on_user_group_id" t.index ["user_group_id"], name: "index_memberships_on_user_group_id"
......
require 'rails_helper'
RSpec.describe DataViewsController, type: :request do
let(:viewer) { create(:user)}
let(:nilm) { create(:nilm, name: 'my_nilm', viewers: [viewer]) }
let(:db) { create(:db, nilm: nilm)}
let(:viewed_streams) { [
create(:db_stream, db: db),
create(:db_stream, db: db)]}
describe 'GET index' do
context 'with authenticated user' do
it 'returns all loadable data views' do
other_nilm = create(:nilm, name: 'other_nilm')
other_db = create(:db, nilm: other_nilm)
other_stream = create(:db_stream, db: other_db)
other_user = create(:user)
service = CreateDataView.new
allowed_view = service.run(
{name: 'allowed'}, [viewed_streams.first.id], other_user)
prohibited_view = service.run(
{name: 'prohibited'}, [other_stream.id], other_user)
my_view = service.run(
{name: 'created'}, viewed_streams.map{|x| x.id}, viewer)
#viewer should receive 'allowed' and 'created'
@auth_headers = viewer.create_new_auth_token
get "/data_views.json", headers: @auth_headers
expect(response).to have_http_status(:ok)
body = JSON.parse(response.body)
expect(body.length).to eq 2
body.each do |view|
if view['name']=='created'
expect(view['owner']).to be true
else
expect(view['owner']).to be false
end
end
end
end
context 'without sign-in' do
it 'returns unauthorized' do
get "/data_views.json"
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'POST create' do
context 'with authenticated user' do
it 'creates a dataview' do
@auth_headers = viewer.create_new_auth_token
post "/data_views.json",
params: {
name: 'test', description: '', image: '', redux_json: '',
stream_ids: viewed_streams.map {|x| x.id}
}, headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(response).to have_notice_message
body = JSON.parse(response.body)
#viewer should own this new dataview
expect(body['data']['owner']).to be(true)
end
it 'returns error with bad parameters' do
@auth_headers = viewer.create_new_auth_token
post "/data_views.json",
params: {
description: 'missing name', image: '', redux_json: '',
stream_ids: viewed_streams.map {|x| x.id}
}, headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message
end
end
context 'without sign-in' do
it 'returns unauthorized' do
post "/data_views.json"
expect(response.status).to eq(401)
end
end
end
end
FactoryGirl.define do
factory :data_view do
name { Faker::Lorem.words(3).join(' ') }
description { Faker::Lorem.sentence }
redux_json "auto generated from factory"
end
end
require 'rails_helper'
RSpec.describe DataView, type: :model do
let(:data_view) { DataView.new }
specify { expect(data_view).to respond_to(:name) }
specify { expect(data_view).to respond_to(:description) }
specify { expect(data_view).to respond_to(:image) }
specify { expect(data_view).to respond_to(:redux_json) }
specify { expect(data_view).to respond_to(:owner) }
specify { expect(data_view).to respond_to(:nilms) }
it 'is deleted when nilm is destroyed' do
nilm1 = create(:nilm)
nilm2 = create(:nilm)
dv = create(:data_view)
dv.nilms = [nilm1, nilm2]
expect(DataView.count).to eq 1
expect(DataViewsNilm.count).to eq 2
nilm1.destroy
expect(DataView.count).to eq 0
expect(DataViewsNilm.count).to eq 0
end
it 'does not delete nilm when destroyed' do
nilm1 = create(:nilm)
nilm2 = create(:nilm)
dv1 = create(:data_view)
dv2 = create(:data_view)
dv1.nilms = [nilm1, nilm2]
dv2.nilms = [nilm1 , nilm2]
expect(DataView.count).to eq 2
expect(DataViewsNilm.count).to eq 4
dv1.destroy
expect(DataView.count).to eq 1
expect(DataViewsNilm.count).to eq 2
expect(Nilm.count).to eq 2
end
end
# frozen_string_literal: true
require 'rails_helper'
describe 'CreateDataView service' do
let(:viewer) { create(:user) }
let(:nilm) { create(:nilm, viewers: [viewer]) }
let(:db) { create(:db, nilm: nilm)}
let(:viewed_streams) { [
create(:db_stream, db: db),
create(:db_stream, db: db)]}
it 'creates a dataview' do
params = {
name: 'test',
description: '',
image: '',
redux_json: ''}
stream_ids = viewed_streams.map {|x| x.id}
service = CreateDataView.new
service.run(params, stream_ids, viewer)
expect(service.success?).to be true
expect(DataView.count).to eq(1)
expect(nilm.data_views.count).to eq(1)
expect(viewer.data_views.count).to eq(1)
end
it 'returns error if dataview is not valid' do
params = {description: 'missing name'}
stream_ids = viewed_streams.map {|x| x.id}
service = CreateDataView.new
service.run(params, stream_ids, viewer)
expect(service.success?).to be false
end
it 'returns error if stream_ids are not valid' do
params = {
name: 'bad stream ids',
description: '',
image: '',
redux_json: ''}
stream_ids = [10,11]
service = CreateDataView.new
service.run(params, stream_ids, viewer)
expect(service.success?).to be false
end
end
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