Commit 908b51a5 by John Donnal

refactor to support 6.0

parent df0f6983
...@@ -35,7 +35,6 @@ gem 'httparty' ...@@ -35,7 +35,6 @@ gem 'httparty'
gem 'rack-cors' gem 'rack-cors'
gem 'devise_token_auth' gem 'devise_token_auth'
gem 'devise_invitable' gem 'devise_invitable'
gem 'omniauth'
gem 'oj' # fast json gem 'oj' # fast json
gem 'mini_magick' gem 'mini_magick'
gem 'bootsnap' gem 'bootsnap'
......
...@@ -14,7 +14,7 @@ module Joule ...@@ -14,7 +14,7 @@ module Joule
# if either is nil, the database is not available # if either is nil, the database is not available
if dbinfo.nil? || schema.nil? if dbinfo.nil? || schema.nil?
add_error("cannot contact node at #{@db.url}") add_error("cannot contact node at #{@db.url}")
@db.update_attributes(available: false) @db.update(available: false)
return self return self
end end
# go through the schema and update the database # go through the schema and update the database
...@@ -35,7 +35,7 @@ module Joule ...@@ -35,7 +35,7 @@ module Joule
end end
attrs[:joule_id] = schema[:id] attrs[:joule_id] = schema[:id]
attrs[:hidden] = false attrs[:hidden] = false
db_folder.update_attributes(attrs) db_folder.update(attrs)
#puts db_folder.parent.id #puts db_folder.parent.id
# update or create subfolders # update or create subfolders
updated_ids = [] updated_ids = []
...@@ -114,7 +114,7 @@ module Joule ...@@ -114,7 +114,7 @@ module Joule
attrs[:total_time] = schema[:data_info][:total_time] attrs[:total_time] = schema[:data_info][:total_time]
attrs[:size_on_disk] = schema[:data_info][:bytes] attrs[:size_on_disk] = schema[:data_info][:bytes]
db_stream.update_attributes(attrs) db_stream.update(attrs)
#db_stream.db_elements.destroy_all #db_stream.db_elements.destroy_all
schema[:elements].each do |element_config| schema[:elements].each do |element_config|
element = db_stream.db_elements.find_by_column(element_config[:index]) element = db_stream.db_elements.find_by_column(element_config[:index])
...@@ -124,7 +124,7 @@ module Joule ...@@ -124,7 +124,7 @@ module Joule
attrs[:display_type] = element_config[:display_type].downcase attrs[:display_type] = element_config[:display_type].downcase
attrs[:column] = element_config[:index] attrs[:column] = element_config[:index]
attrs[:plottable] = true attrs[:plottable] = true
element.update_attributes(attrs) element.update(attrs)
end end
end end
......
...@@ -26,7 +26,7 @@ module Nilmdb ...@@ -26,7 +26,7 @@ module Nilmdb
# update the folder attributes from metadata # update the folder attributes from metadata
info = __read_info_entry(@entries) || {} info = __read_info_entry(@entries) || {}
# if metadata is corrupt, use default values instead # if metadata is corrupt, use default values instead
unless @folder.update_attributes( unless @folder.update(
info.slice(*DbFolder.defined_attributes)) info.slice(*DbFolder.defined_attributes))
@folder.use_default_attributes @folder.use_default_attributes
Rails.logger.warn("corrupt metadata: #{@folder.path}") Rails.logger.warn("corrupt metadata: #{@folder.path}")
......
...@@ -31,7 +31,7 @@ module Nilmdb ...@@ -31,7 +31,7 @@ module Nilmdb
# specified path. # specified path.
def __update_stream(stream, base_entry, decimation_entries) def __update_stream(stream, base_entry, decimation_entries)
# use default attributes if metadata is corrupt # use default attributes if metadata is corrupt
unless stream.update_attributes(base_entry[:attributes]) unless stream.update(base_entry[:attributes])
stream.use_default_attributes stream.use_default_attributes
Rails.logger.warn("corrupt metadata: #{stream.path}") Rails.logger.warn("corrupt metadata: #{stream.path}")
end end
...@@ -58,7 +58,7 @@ module Nilmdb ...@@ -58,7 +58,7 @@ module Nilmdb
level = entry[:path].match(UpdateStream.decimation_tag)[1].to_i level = entry[:path].match(UpdateStream.decimation_tag)[1].to_i
decim = stream.db_decimations.find_by_level(level) decim = stream.db_decimations.find_by_level(level)
decim ||= DbDecimation.new(db_stream: stream, level: level) decim ||= DbDecimation.new(db_stream: stream, level: level)
decim.update_attributes(entry[:attributes]) decim.update(entry[:attributes])
#decim.save! #decim.save!
end end
...@@ -74,7 +74,7 @@ module Nilmdb ...@@ -74,7 +74,7 @@ module Nilmdb
# check if there is stream metadata for column x # check if there is stream metadata for column x
entry = stream_data.select { |meta| meta[:column] == x } entry = stream_data.select { |meta| meta[:column] == x }
# use the metadata if present # use the metadata if present
unless element.update_attributes(entry[0] || {}) unless element.update(entry[0] || {})
element.use_default_attributes element.use_default_attributes
element.save! element.save!
Rails.logger.warn(stream_data) Rails.logger.warn(stream_data)
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
# a folder in the database, may contain one or more DbFiles as files # a folder in the database, may contain one or more DbFiles as files
# and one or more DbFolders as subfolders # and one or more DbFolders as subfolders
class DbFolder < ApplicationRecord class DbFolder < ApplicationRecord
belongs_to :parent, class_name: 'DbFolder' belongs_to :parent, class_name: 'DbFolder', optional: true
belongs_to :db belongs_to :db, optional: false
has_many :subfolders, has_many :subfolders,
class_name: 'DbFolder', class_name: 'DbFolder',
......
class Permission < ApplicationRecord class Permission < ApplicationRecord
#---Associations---- #---Associations----
belongs_to :user belongs_to :user, optional: true
belongs_to :user_group belongs_to :user_group, optional: true
belongs_to :nilm belongs_to :nilm
#---Validations--- #---Validations---
......
class User < ActiveRecord::Base class User < ActiveRecord::Base
#---Attributes------ #---Attributes------
devise :database_authenticatable, :registerable, devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :recoverable, :rememberable, :trackable, :validatable, :invitable
:omniauthable, :invitable
include DeviseTokenAuth::Concerns::User include DeviseTokenAuth::Concerns::User
#---Associations---- #---Associations----
...@@ -13,7 +12,7 @@ class User < ActiveRecord::Base ...@@ -13,7 +12,7 @@ class User < ActiveRecord::Base
has_many :data_views has_many :data_views
has_one :nilm_auth_key has_one :nilm_auth_key
belongs_to :home_data_view, class_name: "DataView", belongs_to :home_data_view, class_name: "DataView",
foreign_key: "home_data_view_id", dependent: :destroy foreign_key: "home_data_view_id", dependent: :destroy, optional: true
#---Validations----- #---Validations-----
validates :first_name, :last_name, :email, :presence => true validates :first_name, :last_name, :email, :presence => true
......
...@@ -26,9 +26,11 @@ class CreateNilm ...@@ -26,9 +26,11 @@ class CreateNilm
# pass NILM url onto database since we are using # pass NILM url onto database since we are using
# a single endpoint (eventually this will be joule) # a single endpoint (eventually this will be joule)
db = Db.new(nilm: @nilm, url: url) db = Db.new(nilm: @nilm, url: url)
db.root_folder = DbFolder.new(db: db, name: 'root')
#everything is valid, save the objects #everything is valid, save the objects
nilm.save! nilm.save!
db.save! db.save!
db.root_folder.save!
#give the owner 'admin' permissions on the nilm #give the owner 'admin' permissions on the nilm
Permission.create(user: owner, nilm: nilm, role: 'admin') Permission.create(user: owner, nilm: nilm, role: 'admin')
#update the database #update the database
......
...@@ -5,7 +5,7 @@ require "rails" ...@@ -5,7 +5,7 @@ require "rails"
require "active_model/railtie" require "active_model/railtie"
# require "active_job/railtie" # require "active_job/railtie"
require "active_record/railtie" require "active_record/railtie"
# require "active_storage/engine" require "active_storage/engine"
require "action_controller/railtie" require "action_controller/railtie"
require "action_mailer/railtie" require "action_mailer/railtie"
# require "action_mailbox/engine" # require "action_mailbox/engine"
......
...@@ -22,7 +22,7 @@ Rails.application.configure do ...@@ -22,7 +22,7 @@ Rails.application.configure do
config.consider_all_requests_local = true config.consider_all_requests_local = true
config.action_controller.perform_caching = false config.action_controller.perform_caching = false
config.cache_store = :null_store config.cache_store = :null_store
# Raise exceptions instead of rendering exception templates. # Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false config.action_dispatch.show_exceptions = false
......
...@@ -19,4 +19,4 @@ ActiveSupport.to_time_preserves_timezone = false ...@@ -19,4 +19,4 @@ ActiveSupport.to_time_preserves_timezone = false
# Require `belongs_to` associations by default. Previous versions had false. # Require `belongs_to` associations by default. Previous versions had false.
Rails.application.config.active_record.belongs_to_required_by_default = false Rails.application.config.active_record.belongs_to_required_by_default = false
Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true #Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
...@@ -29,7 +29,7 @@ Rails.application.config.action_controller.default_protect_from_forgery = true ...@@ -29,7 +29,7 @@ Rails.application.config.action_controller.default_protect_from_forgery = true
# Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and # Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and
# 'f' after migrating old data. # 'f' after migrating old data.
Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true #Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
# Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header. # Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header.
Rails.application.config.active_support.use_sha1_digests = true Rails.application.config.active_support.use_sha1_digests = true
......
...@@ -7,28 +7,28 @@ ...@@ -7,28 +7,28 @@
# Read the Guide for Upgrading Ruby on Rails for more info on each option. # Read the Guide for Upgrading Ruby on Rails for more info on each option.
# Don't force requests from old versions of IE to be UTF-8 encoded. # Don't force requests from old versions of IE to be UTF-8 encoded.
# Rails.application.config.action_view.default_enforce_utf8 = false Rails.application.config.action_view.default_enforce_utf8 = false
# Embed purpose and expiry metadata inside signed and encrypted # Embed purpose and expiry metadata inside signed and encrypted
# cookies for increased security. # cookies for increased security.
# #
# This option is not backwards compatible with earlier Rails versions. # This option is not backwards compatible with earlier Rails versions.
# It's best enabled when your entire app is migrated and stable on 6.0. # It's best enabled when your entire app is migrated and stable on 6.0.
# Rails.application.config.action_dispatch.use_cookies_with_metadata = true Rails.application.config.action_dispatch.use_cookies_with_metadata = true
# Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification. # Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification.
# Rails.application.config.action_dispatch.return_only_media_type_on_content_type = false Rails.application.config.action_dispatch.return_only_media_type_on_content_type = false
# Return false instead of self when enqueuing is aborted from a callback. # Return false instead of self when enqueuing is aborted from a callback.
# Rails.application.config.active_job.return_false_on_aborted_enqueue = true Rails.application.config.active_job.return_false_on_aborted_enqueue = true
# Send Active Storage analysis and purge jobs to dedicated queues. # Send Active Storage analysis and purge jobs to dedicated queues.
# Rails.application.config.active_storage.queues.analysis = :active_storage_analysis Rails.application.config.active_storage.queues.analysis = :active_storage_analysis
# Rails.application.config.active_storage.queues.purge = :active_storage_purge Rails.application.config.active_storage.queues.purge = :active_storage_purge
# When assigning to a collection of attachments declared via `has_many_attached`, replace existing # When assigning to a collection of attachments declared via `has_many_attached`, replace existing
# attachments instead of appending. Use #attach to add new attachments without replacing existing ones. # attachments instead of appending. Use #attach to add new attachments without replacing existing ones.
# Rails.application.config.active_storage.replace_on_assign_to_many = true Rails.application.config.active_storage.replace_on_assign_to_many = true
# Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail. # Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail.
# #
...@@ -37,9 +37,9 @@ ...@@ -37,9 +37,9 @@
# If you send mail in the background, job workers need to have a copy of # If you send mail in the background, job workers need to have a copy of
# MailDeliveryJob to ensure all delivery jobs are processed properly. # MailDeliveryJob to ensure all delivery jobs are processed properly.
# Make sure your entire app is migrated and stable on 6.0 before using this setting. # Make sure your entire app is migrated and stable on 6.0 before using this setting.
# Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob" Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"
# Enable the same cache key to be reused when the object being cached of type # Enable the same cache key to be reused when the object being cached of type
# `ActiveRecord::Relation` changes by moving the volatile information (max updated at and count) # `ActiveRecord::Relation` changes by moving the volatile information (max updated at and count)
# of the relation's cache key into the cache version to support recycling cache key. # of the relation's cache key into the cache version to support recycling cache key.
# Rails.application.config.active_record.collection_cache_versioning = true Rails.application.config.active_record.collection_cache_versioning = true
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
# of editing this file, please use the migrations feature of Active Record to # of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition. # incrementally modify your database, and then regenerate this schema definition.
# #
# Note that this schema.rb definition is the authoritative source for your # This file is the source Rails uses to define your schema when running `rails
# database schema. If you need to create the application database on another # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
# system, you should be using db:schema:load, not running all the migrations # be faster and is potentially less error prone than running all of your
# from scratch. The latter is a flawed and unsustainable approach (the more migrations # migrations from scratch. Old migrations may fail to apply correctly if those
# you'll amass, the slower it'll run and the greater likelihood for issues). # migrations use external dependencies or application code.
# #
# 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.
......
...@@ -24,7 +24,9 @@ describe Joule::Adapter do ...@@ -24,7 +24,9 @@ describe Joule::Adapter do
json = JSON.parse(raw) json = JSON.parse(raw)
expect(mock_backend).to receive(:get_annotations) { json } expect(mock_backend).to receive(:get_annotations) { json }
stream = FactoryBot.create(:db_stream, name: 'test_stream') nilm = FactoryBot.create(:nilm, name: "test")
stream = FactoryBot.create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder,
name: 'test_stream')
annotations = adapter.get_annotations(stream) annotations = adapter.get_annotations(stream)
expect(annotations.length).to eq 6 expect(annotations.length).to eq 6
annotations.each do | annotation | annotations.each do | annotation |
......
...@@ -78,7 +78,9 @@ describe Joule::Backend do ...@@ -78,7 +78,9 @@ describe Joule::Backend do
describe "create_annotation" do describe "create_annotation" do
it 'creates annotations', :vcr do it 'creates annotations', :vcr do
backend = Joule::Backend.new(url, key) backend = Joule::Backend.new(url, key)
stream = FactoryBot.create(:db_stream, name: 'test_stream') nilm = FactoryBot.create(:nilm, name: "test")
stream = FactoryBot.create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder,
name: 'test_stream')
stream.joule_id = 2646 stream.joule_id = 2646
annotation = FactoryBot.build(:annotation, db_stream: stream) annotation = FactoryBot.build(:annotation, db_stream: stream)
backend.create_annotation(annotation) backend.create_annotation(annotation)
......
...@@ -6,7 +6,9 @@ describe Nilmdb::Adapter do ...@@ -6,7 +6,9 @@ describe Nilmdb::Adapter do
it 'creates annotations' do it 'creates annotations' do
stream = FactoryBot.create(:db_stream, name: 'test_stream') nilm = FactoryBot.create(:nilm, name: "test")
stream = FactoryBot.create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder,
name: 'test_stream')
annotation = FactoryBot.build(:annotation, title: 'test', db_stream: stream) annotation = FactoryBot.build(:annotation, title: 'test', db_stream: stream)
adapter = Nilmdb::Adapter.new("url") adapter = Nilmdb::Adapter.new("url")
...@@ -23,7 +25,9 @@ describe Nilmdb::Adapter do ...@@ -23,7 +25,9 @@ describe Nilmdb::Adapter do
expect(annotation.id).to eq 251 expect(annotation.id).to eq 251
end end
it 'creates first annotation' do it 'creates first annotation' do
stream = FactoryBot.create(:db_stream, name: 'test_stream') nilm = FactoryBot.create(:nilm, name: "test")
stream = FactoryBot.create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder,
name: 'test_stream')
annotation = FactoryBot.build(:annotation, title: 'test', db_stream: stream) annotation = FactoryBot.build(:annotation, title: 'test', db_stream: stream)
adapter = Nilmdb::Adapter.new("url") adapter = Nilmdb::Adapter.new("url")
...@@ -44,7 +48,9 @@ describe Nilmdb::Adapter do ...@@ -44,7 +48,9 @@ describe Nilmdb::Adapter do
json = JSON.parse(raw) json = JSON.parse(raw)
expect(mock_backend).to receive(:read_annotations) { json } expect(mock_backend).to receive(:read_annotations) { json }
stream = FactoryBot.create(:db_stream, name: 'test_stream') nilm = FactoryBot.create(:nilm, name: "test")
stream = FactoryBot.create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder,
name: 'test_stream')
annotations = adapter.get_annotations(stream) annotations = adapter.get_annotations(stream)
expect(annotations.length).to eq 6 expect(annotations.length).to eq 6
annotations.each do | annotation | annotations.each do | annotation |
...@@ -52,7 +58,9 @@ describe Nilmdb::Adapter do ...@@ -52,7 +58,9 @@ describe Nilmdb::Adapter do
end end
end end
it 'deletes annotations' do it 'deletes annotations' do
stream = FactoryBot.create(:db_stream, name: 'test_stream') nilm = FactoryBot.create(:nilm, name: "test")
stream = FactoryBot.create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder,
name: 'test_stream')
annotation = FactoryBot.build(:annotation, title: 'test', db_stream: stream) annotation = FactoryBot.build(:annotation, title: 'test', db_stream: stream)
adapter = Nilmdb::Adapter.new("url") adapter = Nilmdb::Adapter.new("url")
mock_backend = instance_double(Nilmdb::Backend) mock_backend = instance_double(Nilmdb::Backend)
......
...@@ -18,7 +18,9 @@ describe Nilmdb::Backend do ...@@ -18,7 +18,9 @@ describe Nilmdb::Backend do
it 'retrieves stream specific schema', :vcr do it 'retrieves stream specific schema', :vcr do
backend = Nilmdb::Backend.new(url) backend = Nilmdb::Backend.new(url)
entries = backend.stream_info(create(:db_stream,path:"/tutorial/pump-prep")) nilm = FactoryBot.create(:nilm, name: "test")
entries = backend.stream_info(create(:db_stream,db: nilm.db, db_folder: nilm.db.root_folder,
path:"/tutorial/pump-prep"))
expect(entries[:base_entry][:path]).to eq "/tutorial/pump-prep" expect(entries[:base_entry][:path]).to eq "/tutorial/pump-prep"
#TODO: support decimation lookup, need HTTP API to process wild cards #TODO: support decimation lookup, need HTTP API to process wild cards
expect(entries[:decimation_entries].length).to eq 0 expect(entries[:decimation_entries].length).to eq 0
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'LoadStreamData' do RSpec.describe 'LoadStreamData' do
let(:db) { create(:db, max_points_per_plot: 100) } let(:nilm) { create(:nilm, name: "test")}
let(:db) { create(:db, nilm: nilm, max_points_per_plot: 100) }
describe 'rapid decimation algorithm' do describe 'rapid decimation algorithm' do
it 'computes decimation level' do it 'computes decimation level' do
...@@ -27,12 +28,13 @@ RSpec.describe 'LoadStreamData' do ...@@ -27,12 +28,13 @@ RSpec.describe 'LoadStreamData' do
nil, nil,
[50,0,1,2,-1,0,1,1,2,3]] [50,0,1,2,-1,0,1,1,2,3]]
@db_stream = create(:db_stream, elements_count: 0, @db_stream = create(:db_stream, elements_count: 0,
db: db, decimations_count: 3, # lvl64 db: db, db_folder: db.root_folder,
decimations_count: 3, # lvl64
start_time: 0, end_time: 100) start_time: 0, end_time: 100)
#create the db elements #create the db elements
types = ['discrete','continuous','event'] types = ['discrete','continuous','event']
3.times do |i| 3.times do |i|
@db_stream.db_elements << create(:db_element, @db_stream.db_elements << build(:db_element,
column: i, offset: i+1, scale_factor:i+2, display_type: types[i]) column: i, offset: i+1, scale_factor:i+2, display_type: types[i])
end end
...@@ -108,11 +110,12 @@ RSpec.describe 'LoadStreamData' do ...@@ -108,11 +110,12 @@ RSpec.describe 'LoadStreamData' do
nil, nil,
[110,0],[115,0]] [110,0],[115,0]]
@db_stream = create(:db_stream, elements_count: 0, @db_stream = create(:db_stream, elements_count: 0,
db: db, decimations_count: 1, # lvl4 db: db, db_folder: db.root_folder,
decimations_count: 1, # lvl4
start_time: 0, end_time: 100) start_time: 0, end_time: 100)
#create the db elements #create the db elements
3.times do |i| 3.times do |i|
@db_stream.db_elements << create(:db_element, @db_stream.db_elements << build(:db_element,
column: i, offset: i+1, scale_factor:i+2) column: i, offset: i+1, scale_factor:i+2)
end end
@mockAdapter = MockDataDbAdapter.new( @mockAdapter = MockDataDbAdapter.new(
...@@ -143,11 +146,12 @@ RSpec.describe 'LoadStreamData' do ...@@ -143,11 +146,12 @@ RSpec.describe 'LoadStreamData' do
before do before do
@data = [[40,0,1,2],nil,[50,0,1,2]] @data = [[40,0,1,2],nil,[50,0,1,2]]
@db_stream = create(:db_stream, elements_count: 0, @db_stream = create(:db_stream, elements_count: 0,
db: db, decimations_count: 3, # lvl64 db: db, db_folder: db.root_folder,
decimations_count: 3, # lvl64
start_time: 0, end_time: 100) start_time: 0, end_time: 100)
#create the db elements #create the db elements
3.times do |i| 3.times do |i|
@db_stream.db_elements << create(:db_element, @db_stream.db_elements << build(:db_element,
column: i, offset: i+1, scale_factor:i+2) column: i, offset: i+1, scale_factor:i+2)
end end
@mockAdapter = MockDataDbAdapter.new( @mockAdapter = MockDataDbAdapter.new(
...@@ -194,12 +198,13 @@ RSpec.describe 'LoadStreamData' do ...@@ -194,12 +198,13 @@ RSpec.describe 'LoadStreamData' do
describe 'when data is not present' do describe 'when data is not present' do
before do before do
@data = [1, 2, 3] @data = [1, 2, 3]
@db_stream = create(:db_stream, elements_count: 0, @db_stream = create(:db_stream, db_folder: db.root_folder,
elements_count: 0,
db: db, decimations_count: 4, # lvl64 db: db, decimations_count: 4, # lvl64
start_time: 100, end_time: 200) start_time: 100, end_time: 200)
#create the db elements #create the db elements
3.times do |i| 3.times do |i|
@db_stream.db_elements << create(:db_element, @db_stream.db_elements << build(:db_element,
column: i, offset: i+1, scale_factor:i+2) column: i, offset: i+1, scale_factor:i+2)
end end
@mockAdapter = MockDataDbAdapter.new( @mockAdapter = MockDataDbAdapter.new(
......
...@@ -25,9 +25,10 @@ simple_db = [ ...@@ -25,9 +25,10 @@ simple_db = [
describe 'UpdateDb' do describe 'UpdateDb' do
let(:dbinfo) { {} } let(:dbinfo) { {} }
let(:nilm) { create(:nilm, name: "test")}
describe '*run*' do describe '*run*' do
def update_with_schema(schema, db: nil) def update_with_schema(schema, db: nil)
@db = db || Db.new @db = db || create(:db, nilm: nilm)
@service = Nilmdb::UpdateDb.new(@db) @service = Nilmdb::UpdateDb.new(@db)
@service.run(dbinfo, schema) #ignore dbinfo @service.run(dbinfo, schema) #ignore dbinfo
@root = @db.root_folder @root = @db.root_folder
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
require 'rails_helper' require 'rails_helper'
describe 'UpdateFolder service' do describe 'UpdateFolder service' do
let(:db) { Db.new } let(:nilm) {create(:nilm, name: "test")}
let(:db) { create(:db, nilm: nilm)}
let(:service) { Nilmdb::UpdateDb.new(db) } let(:service) { Nilmdb::UpdateDb.new(db) }
let(:helper) { DbSchemaHelper.new } let(:helper) { DbSchemaHelper.new }
let(:mock_dbinfo) { {} } let(:mock_dbinfo) { {} }
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
require 'rails_helper' require 'rails_helper'
describe 'UpdateStream service' do describe 'UpdateStream service' do
let(:db) { Db.new } let(:nilm) {create(:nilm, name: "test")}
let(:db) { create(:db, nilm: nilm)}
let(:service) { Nilmdb::UpdateDb.new(db) } let(:service) { Nilmdb::UpdateDb.new(db) }
let(:helper) { DbSchemaHelper.new } let(:helper) { DbSchemaHelper.new }
let(:mock_dbinfo) { {} } let(:mock_dbinfo) { {} }
......
...@@ -10,7 +10,7 @@ RSpec.describe AnnotationsController, type: :request do ...@@ -10,7 +10,7 @@ RSpec.describe AnnotationsController, type: :request do
admins: [admin], owners: [owner], viewers: [viewer]) admins: [admin], owners: [owner], viewers: [viewer])
end end
let(:db) {create(:db, nilm: nilm)} let(:db) {create(:db, nilm: nilm)}
let(:stream) {create(:db_stream, db: db)} let(:stream) {create(:db_stream, db: db, db_folder: db.root_folder)}
describe 'GET #annotations' do describe 'GET #annotations' do
# retrieve annotations for a given stream # retrieve annotations for a given stream
......
...@@ -6,15 +6,15 @@ RSpec.describe DataViewsController, type: :request do ...@@ -6,15 +6,15 @@ RSpec.describe DataViewsController, type: :request do
let(:nilm) { create(:nilm, name: 'my_nilm', viewers: [viewer]) } let(:nilm) { create(:nilm, name: 'my_nilm', viewers: [viewer]) }
let(:db) { create(:db, nilm: nilm)} let(:db) { create(:db, nilm: nilm)}
let(:viewed_streams) { [ let(:viewed_streams) { [
create(:db_stream, db: db), create(:db_stream, db: db, db_folder: db.root_folder),
create(:db_stream, db: db)]} create(:db_stream, db: db, db_folder: db.root_folder)]}
describe 'GET index' do describe 'GET index' do
context 'with authenticated user' do context 'with authenticated user' do
it 'returns all loadable data views' do it 'returns all loadable data views' do
other_nilm = create(:nilm, name: 'other_nilm') other_nilm = create(:nilm, name: 'other_nilm')
other_db = create(:db, nilm: other_nilm) other_db = create(:db, nilm: other_nilm)
other_stream = create(:db_stream, db: other_db) other_stream = create(:db_stream, db: other_db, db_folder: other_db.root_folder)
other_user = create(:user) other_user = create(:user)
service = CreateDataView.new service = CreateDataView.new
service.run( service.run(
...@@ -49,10 +49,10 @@ RSpec.describe DataViewsController, type: :request do ...@@ -49,10 +49,10 @@ RSpec.describe DataViewsController, type: :request do
context 'with authenticated user' do context 'with authenticated user' do
it 'returns user home data view' do it 'returns user home data view' do
user1 = create(:user) user1 = create(:user)
dv1 = create(:data_view) dv1 = create(:data_view, owner: user1)
user1.update(home_data_view: dv1) user1.update(home_data_view: dv1)
user2 = create(:user) user2 = create(:user)
dv2 = create(:data_view) dv2 = create(:data_view, owner: user2)
user2.update(home_data_view: dv2) user2.update(home_data_view: dv2)
#user1 gets his view #user1 gets his view
@auth_headers = user1.create_new_auth_token @auth_headers = user1.create_new_auth_token
......
...@@ -12,10 +12,8 @@ RSpec.describe DbElementsController, type: :request do ...@@ -12,10 +12,8 @@ RSpec.describe DbElementsController, type: :request do
stream = create(:db_stream, elements_count: 0, stream = create(:db_stream, elements_count: 0,
db: nilm.db, db: nilm.db,
db_folder: nilm.db.root_folder) db_folder: nilm.db.root_folder)
@elem1 = create(:db_element) @elem1 = create(:db_element, db_stream: stream)
@elem2 = create(:db_element) @elem2 = create(:db_element, db_stream: stream)
stream.db_elements << @elem1
stream.db_elements << @elem2
end end
it "returns elements with data" do it "returns elements with data" do
@service_data = [{ id: @elem1.id, data: 'mock1' }, @service_data = [{ id: @elem1.id, data: 'mock1' },
...@@ -76,8 +74,7 @@ RSpec.describe DbElementsController, type: :request do ...@@ -76,8 +74,7 @@ RSpec.describe DbElementsController, type: :request do
stream2 = create(:db_stream, elements_count: 0, stream2 = create(:db_stream, elements_count: 0,
db: nilm2.db, db: nilm2.db,
db_folder: nilm2.db.root_folder) db_folder: nilm2.db.root_folder)
@elem3 = create(:db_element) @elem3 = create(:db_element, db_stream: stream2)
stream2.db_elements << @elem3
@auth_headers = user1.create_new_auth_token @auth_headers = user1.create_new_auth_token
get '/db_elements/data.json', get '/db_elements/data.json',
......
...@@ -16,11 +16,11 @@ RSpec.describe DbStreamsController, type: :request do ...@@ -16,11 +16,11 @@ RSpec.describe DbStreamsController, type: :request do
let(:viewer) {create(:user)} let(:viewer) {create(:user)}
let(:nilm) {create(:nilm, viewers: [viewer])} let(:nilm) {create(:nilm, viewers: [viewer])}
let(:db) {create(:db, nilm: nilm)} let(:db) {create(:db, nilm: nilm)}
let(:stream2) {create(:db_stream, db: db)} let(:stream2) {create(:db_stream, db: db, db_folder: db.root_folder)}
let(:stream1) {create(:db_stream, db: db)} let(:stream1) {create(:db_stream, db: db, db_folder: db.root_folder)}
let(:other_nilm) {create(:nilm)} let(:other_nilm) {create(:nilm)}
let(:other_db) {create(:db, nilm: other_nilm)} let(:other_db) {create(:db, nilm: other_nilm)}
let(:other_stream) {create(:db_stream, db: other_db)} let(:other_stream) {create(:db_stream, db: other_db, db_folder: other_db.root_folder)}
context 'with viewer permissions' do context 'with viewer permissions' do
it 'returns array of requested streams' do it 'returns array of requested streams' do
......
...@@ -126,8 +126,8 @@ RSpec.describe NilmsController, type: :request do ...@@ -126,8 +126,8 @@ RSpec.describe NilmsController, type: :request do
end end
end end
it 'returns data apps as json' do it 'returns data apps as json' do
test_app = create(:data_app, name: 'test') test_app = create(:data_app, name: 'test', nilm: john_nilm)
john_nilm.data_apps << test_app #john_nilm.data_apps << test_app
get "/nilms/#{john_nilm.id}.json", get "/nilms/#{john_nilm.id}.json",
headers: john.create_new_auth_token headers: john.create_new_auth_token
body = JSON.parse(response.body) body = JSON.parse(response.body)
......
...@@ -10,5 +10,7 @@ FactoryBot.define do ...@@ -10,5 +10,7 @@ FactoryBot.define do
size_on_disk { Faker::Number.number(digits: 6) } size_on_disk { Faker::Number.number(digits: 6) }
hidden { false } hidden { false }
path { "/root/#{Faker::Lorem.word}/#{Faker::Number.unique.number(digits: 4)}" } path { "/root/#{Faker::Lorem.word}/#{Faker::Number.unique.number(digits: 4)}" }
end end
end end
...@@ -8,6 +8,10 @@ FactoryBot.define do ...@@ -8,6 +8,10 @@ FactoryBot.define do
size_other { Faker::Number.number(digits: 5) } size_other { Faker::Number.number(digits: 5) }
size_total { size_db + size_other } size_total { size_db + size_other }
available { true } available { true }
root_folder #root_folder
before(:create) do |db, evaluator|
db.root_folder = create :db_folder, db: db, name: "root"
end
end end
end end
...@@ -4,12 +4,13 @@ FactoryBot.define do ...@@ -4,12 +4,13 @@ FactoryBot.define do
factory :nilm do factory :nilm do
db #db
name {Faker::Lorem.unique.words(number: 3).join(' ')} name {Faker::Lorem.unique.words(number: 3).join(' ')}
description { Faker::Lorem.sentence } description { Faker::Lorem.sentence }
url {Faker::Internet.unique.url} url {Faker::Internet.unique.url}
node_type { 'nilmdb' } node_type { 'nilmdb' }
key {Faker::Lorem.characters(number: 20)} key {Faker::Lorem.characters(number: 20)}
transient do transient do
admins { [] } admins { [] }
owners { [] } owners { [] }
...@@ -17,6 +18,9 @@ FactoryBot.define do ...@@ -17,6 +18,9 @@ FactoryBot.define do
end end
after(:create) do |nilm, evaluator| after(:create) do |nilm, evaluator|
#root_folder = build :db_folder
create :db, nilm: nilm
evaluator.admins.each do |admin| evaluator.admins.each do |admin|
if admin.instance_of? User if admin.instance_of? User
create(:permission, user: admin, user_group: nil, nilm: nilm, role: "admin") create(:permission, user: admin, user_group: nil, nilm: nilm, role: "admin")
......
...@@ -13,7 +13,8 @@ RSpec.describe DataView, type: :model do ...@@ -13,7 +13,8 @@ RSpec.describe DataView, type: :model do
it 'is deleted when nilm is destroyed' do it 'is deleted when nilm is destroyed' do
nilm1 = create(:nilm) nilm1 = create(:nilm)
nilm2 = create(:nilm) nilm2 = create(:nilm)
dv = create(:data_view) owner = create(:user)
dv = create(:data_view, owner: owner)
dv.nilms = [nilm1, nilm2] dv.nilms = [nilm1, nilm2]
expect(DataView.count).to eq 1 expect(DataView.count).to eq 1
expect(DataViewsNilm.count).to eq 2 expect(DataViewsNilm.count).to eq 2
...@@ -25,8 +26,9 @@ RSpec.describe DataView, type: :model do ...@@ -25,8 +26,9 @@ RSpec.describe DataView, type: :model do
it 'does not delete nilm when destroyed' do it 'does not delete nilm when destroyed' do
nilm1 = create(:nilm) nilm1 = create(:nilm)
nilm2 = create(:nilm) nilm2 = create(:nilm)
dv1 = create(:data_view) owner = create(:user)
dv2 = create(:data_view) dv1 = create(:data_view, owner: owner)
dv2 = create(:data_view, owner: owner)
dv1.nilms = [nilm1, nilm2] dv1.nilms = [nilm1, nilm2]
dv2.nilms = [nilm1 , nilm2] dv2.nilms = [nilm1 , nilm2]
expect(DataView.count).to eq 2 expect(DataView.count).to eq 2
......
...@@ -22,8 +22,9 @@ RSpec.describe 'DbElement' do ...@@ -22,8 +22,9 @@ RSpec.describe 'DbElement' do
expect(element.errors[:name].any?).to be true expect(element.errors[:name].any?).to be true
end end
it 'name is unique in stream' do it 'name is unique in stream' do
stream = FactoryBot.create(:db_stream, name: 'parent') nilm = FactoryBot.create(:nilm, name: "test")
elem1 = FactoryBot.create(:db_element, name: 'shared', db_stream: stream) stream = FactoryBot.create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder, name: 'parent')
FactoryBot.create(:db_element, name: 'shared', db_stream: stream)
elem2 = FactoryBot.build(:db_element, name: 'shared', db_stream: stream) elem2 = FactoryBot.build(:db_element, name: 'shared', db_stream: stream)
elem2.validate elem2.validate
expect(elem2.errors[:name].any?).to be true expect(elem2.errors[:name].any?).to be true
......
...@@ -36,8 +36,9 @@ RSpec.describe 'DbFolder' do ...@@ -36,8 +36,9 @@ RSpec.describe 'DbFolder' do
end end
describe 'insert_stream' do describe 'insert_stream' do
let(:db_folder) { FactoryBot.create(:db_folder) } let(:nilm) { FactoryBot.create(:nilm)}
let(:new_stream) { FactoryBot.create(:db_stream) } let(:db_folder) { FactoryBot.create(:db_folder, db: nilm.db) }
let(:new_stream) { FactoryBot.build(:db_stream) }
it 'adds the stream to the folder' do it 'adds the stream to the folder' do
db_folder.insert_stream(stream: new_stream) db_folder.insert_stream(stream: new_stream)
...@@ -46,7 +47,8 @@ RSpec.describe 'DbFolder' do ...@@ -46,7 +47,8 @@ RSpec.describe 'DbFolder' do
end end
describe 'validation' do describe 'validation' do
let(:db_folder) { FactoryBot.create(:db_folder) } let(:nilm) { FactoryBot.create(:nilm)}
let(:db_folder) { FactoryBot.create(:db_folder, db: nilm.db) }
it 'forbids an empty name' do it 'forbids an empty name' do
db_folder.name = '' db_folder.name = ''
expect(db_folder.valid?).to be false expect(db_folder.valid?).to be false
......
...@@ -24,14 +24,16 @@ RSpec.describe 'DbStream' do ...@@ -24,14 +24,16 @@ RSpec.describe 'DbStream' do
expect(stream.errors[:name].any?).to be true expect(stream.errors[:name].any?).to be true
end end
it 'requires a unique name' do it 'requires a unique name' do
folder = DbFolder.create(name: 'parent') nilm = create(:nilm, name: "Test")
DbStream.create(name: 'stream', db_folder: folder) DbStream.create(name: 'stream', db: nilm.db, db_folder: nilm.db.root_folder)
stream2 = DbStream.new(name: 'stream', db_folder: folder) stream2 = DbStream.new(name: 'stream', db: nilm.db, db_folder: nilm.db.root_folder)
stream2.validate stream2.validate
expect(stream2.errors[:name].any?).to be true expect(stream2.errors[:name].any?).to be true
end end
it 'requires a valid data type' do it 'requires a valid data type' do
my_stream = create(:db_stream, name: 'invalid') nilm = create(:nilm, name: "Test")
my_stream = create(:db_stream, db: nilm.db,
db_folder: nilm.db.root_folder, name: 'invalid')
my_stream.data_type = "float32_5" my_stream.data_type = "float32_5"
expect(my_stream).to_not be_valid expect(my_stream).to_not be_valid
expect(my_stream.errors.full_messages[0]).to include "5 elements" expect(my_stream.errors.full_messages[0]).to include "5 elements"
...@@ -49,13 +51,17 @@ RSpec.describe 'DbStream' do ...@@ -49,13 +51,17 @@ RSpec.describe 'DbStream' do
describe 'meta_attributes' do describe 'meta_attributes' do
it 'parses data format' do it 'parses data format' do
my_stream = create(:db_stream, name: 'invalid') nilm = create(:nilm, name: "Test")
my_stream = create(:db_stream, db: nilm.db,
db_folder: nilm.db.root_folder, name: 'invalid')
my_stream.data_type="uint8_4" my_stream.data_type="uint8_4"
expect(my_stream).to be_valid expect(my_stream).to be_valid
expect(my_stream.data_format).to eq "uint8" expect(my_stream.data_format).to eq "uint8"
end end
it 'parses column count' do it 'parses column count' do
my_stream = create(:db_stream, name: 'invalid', elements_count: 8) nilm = create(:nilm, name: "Test")
my_stream = create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder,
name: 'invalid', elements_count: 8)
expect(my_stream.column_count).to eq 8 expect(my_stream.column_count).to eq 8
end end
end end
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'BuildDataset' do RSpec.describe 'BuildDataset' do
let(:db) { create(:db, max_points_per_plot: 100) } let(:nilm) {create(:nilm, name: 'test')}
let(:db_stream) { create(:db_stream, db: db, elements_count: 0) } let(:db) { create(:db, nilm: nilm, max_points_per_plot: 100) }
let(:db_stream) { create(:db_stream, db_folder: db.root_folder, db: db, elements_count: 0) }
let(:elem0) { create(:db_element, name: 'e0_continuous', display_type: 'continuous', column: 0, units: 'c', db_stream: db_stream) } let(:elem0) { create(:db_element, name: 'e0_continuous', display_type: 'continuous', column: 0, units: 'c', db_stream: db_stream) }
let(:elem1) { create(:db_element, name: 'e1_discrete', display_type: 'discrete', column: 1, units: 'd', db_stream: db_stream) } let(:elem1) { create(:db_element, name: 'e1_discrete', display_type: 'discrete', column: 1, units: 'd', db_stream: db_stream) }
let(:elem2) { create(:db_element, name: 'e2_event', display_type: 'event', column: 2, units: nil, db_stream: db_stream) } let(:elem2) { create(:db_element, name: 'e2_event', display_type: 'event', column: 2, units: nil, db_stream: db_stream) }
......
...@@ -3,12 +3,13 @@ require 'rails_helper' ...@@ -3,12 +3,13 @@ require 'rails_helper'
RSpec.describe 'LoadElementData' do RSpec.describe 'LoadElementData' do
let(:db) { create(:db, max_points_per_plot: 100) } let(:nilm) {create(:nilm, name: 'test')}
let(:db) { create(:db, nilm: nilm, max_points_per_plot: 100) }
describe 'when elements are from the same stream' do describe 'when elements are from the same stream' do
before do before do
db = create(:db, url: 'http://test/nilmdb') db = create(:db, nilm: nilm, url: 'http://test/nilmdb')
@db_stream = create(:db_stream, db: db, elements_count: 0) @db_stream = create(:db_stream, db_folder: db.root_folder, db: db, elements_count: 0)
@elem0 = create(:db_element, column: 0, db_stream: @db_stream) @elem0 = create(:db_element, column: 0, db_stream: @db_stream)
@elem1 = create(:db_element, column: 1, db_stream: @db_stream) @elem1 = create(:db_element, column: 1, db_stream: @db_stream)
@elem2 = create(:db_element, column: 2, db_stream: @db_stream) @elem2 = create(:db_element, column: 2, db_stream: @db_stream)
...@@ -30,13 +31,13 @@ RSpec.describe 'LoadElementData' do ...@@ -30,13 +31,13 @@ RSpec.describe 'LoadElementData' do
describe 'when elements are from different streams' do describe 'when elements are from different streams' do
before do before do
db = create(:db, url: 'http://test/nilmdb') db = create(:db, nilm: nilm, url: 'http://test/nilmdb')
@db_stream1 = create(:db_stream, db: db, elements_count: 0) @db_stream1 = create(:db_stream, db_folder: db.root_folder, db: db, elements_count: 0)
@elem0 = create(:db_element, column: 0, db_stream: @db_stream1) @elem0 = create(:db_element, column: 0, db_stream: @db_stream1)
@elem1 = create(:db_element, column: 1, db_stream: @db_stream1) @elem1 = create(:db_element, column: 1, db_stream: @db_stream1)
@stream1_data = [{id: @elem0.id, values: 'mock0'}, @stream1_data = [{id: @elem0.id, values: 'mock0'},
{id: @elem1.id, values: 'mock1'}] {id: @elem1.id, values: 'mock1'}]
@db_stream2 = create(:db_stream, db: db, elements_count: 0) @db_stream2 = create(:db_stream, db_folder: db.root_folder, db: db, elements_count: 0)
@elem2 = create(:db_element, column: 2, db_stream: @db_stream2) @elem2 = create(:db_element, column: 2, db_stream: @db_stream2)
@elem3 = create(:db_element, column: 3, db_stream: @db_stream2) @elem3 = create(:db_element, column: 3, db_stream: @db_stream2)
@stream2_data = [{id: @elem2.id, values: 'mock2'}, @stream2_data = [{id: @elem2.id, values: 'mock2'},
...@@ -61,7 +62,7 @@ RSpec.describe 'LoadElementData' do ...@@ -61,7 +62,7 @@ RSpec.describe 'LoadElementData' do
describe 'when a nilm does not respond' do describe 'when a nilm does not respond' do
before do before do
db = create(:db, url: 'http://test/nilmdb') db = create(:db, nilm: nilm, url: 'http://test/nilmdb')
@db_stream1 = create(:db_stream, db: db, db_folder: db.root_folder, @db_stream1 = create(:db_stream, db: db, db_folder: db.root_folder,
elements_count: 0) elements_count: 0)
@elem0 = create(:db_element, column: 0, db_stream: @db_stream1) @elem0 = create(:db_element, column: 0, db_stream: @db_stream1)
......
...@@ -7,8 +7,8 @@ describe 'CreateDataView service' do ...@@ -7,8 +7,8 @@ describe 'CreateDataView service' do
let(:nilm) { create(:nilm, viewers: [viewer]) } let(:nilm) { create(:nilm, viewers: [viewer]) }
let(:db) { create(:db, nilm: nilm)} let(:db) { create(:db, nilm: nilm)}
let(:viewed_streams) { [ let(:viewed_streams) { [
create(:db_stream, db: db), create(:db_stream, db: db, db_folder: db.root_folder),
create(:db_stream, db: db)]} create(:db_stream, db: db, db_folder: db.root_folder)]}
describe 'successfully' do describe 'successfully' do
before do before do
......
...@@ -4,7 +4,9 @@ require 'rails_helper' ...@@ -4,7 +4,9 @@ require 'rails_helper'
describe 'EditStream service' do describe 'EditStream service' do
let(:mock_adapter) { instance_double(Nilmdb::Adapter) } let(:mock_adapter) { instance_double(Nilmdb::Adapter) }
let(:stream) { FactoryBot.create(:db_stream, path: '/stream/path', name: 'old') } let(:nilm) {create(:nilm, name: "test")}
let(:stream) { FactoryBot.create(:db_stream, db: nilm.db, db_folder: nilm.db.root_folder,
path: '/stream/path', name: 'old') }
let(:element) { stream.db_elements.first} let(:element) { stream.db_elements.first}
let(:service) { EditStream.new(mock_adapter) } let(:service) { EditStream.new(mock_adapter) }
# db backend return values # db backend return values
......
...@@ -4,7 +4,8 @@ require 'rails_helper' ...@@ -4,7 +4,8 @@ require 'rails_helper'
describe 'EditFolder service' do describe 'EditFolder service' do
let(:mock_adapter) { instance_double(Nilmdb::Adapter) } let(:mock_adapter) { instance_double(Nilmdb::Adapter) }
let(:folder) { DbFolder.new(path: '/folder/path', name: 'old') } let(:nilm) { create(:nilm, name: "test")}
let(:folder) { DbFolder.new(path: '/folder/path', db:nilm.db, name: 'old') }
let(:service) { EditFolder.new(mock_adapter) } let(:service) { EditFolder.new(mock_adapter) }
# mock_adapter return values # mock_adapter return values
let(:success) { { error: false, msg: '' } } let(:success) { { error: false, msg: '' } }
......
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