[UNSTABLE] Add `permissions` table.

pull/909/head
Rick Carlino 2018-07-11 09:44:52 -05:00
parent 3aa6772187
commit f3f1782c2e
18 changed files with 151 additions and 28 deletions

View File

@ -1,6 +1,8 @@
module Api
class SequencesController < Api::AbstractController
PUBLIC_SEQUENCES = Sequence.with_usage_reports.where public: true
PUBLIC_SEQUENCES = Sequence
.with_usage_reports
.where(is_public: true)
SERIALIZED_PUBLIC_SEQUENCES = PUBLIC_SEQUENCES.to_a.map do |s|
CeleryScript::FetchCelery.run!(sequence: s)
end

View File

@ -93,7 +93,7 @@ module CeleryScript
args: Sequence::DEFAULT_ARGS,
color: sequence.color,
name: sequence.name,
public: (sequence.public || false),
public: (sequence.is_public || false),
}
end

View File

@ -10,15 +10,16 @@ module CeleryScriptSettingsBag
PLANT_STAGES = %w(planned planted harvested)
ALLOWED_PIN_MODES = [DIGITAL = 0, ANALOG = 1]
ALLOWED_PIN_TYPES = [Peripheral, Sensor].map(&:name)
ALLOWED_RPC_NODES = %w(home emergency_lock emergency_unlock read_status
sync check_updates power_off reboot toggle_pin
config_update calibrate execute move_absolute
move_relative write_pin read_pin send_message
factory_reset execute_script set_user_env wait
install_farmware update_farmware take_photo zero
install_first_party_farmware remove_farmware
find_home register_gpio unregister_gpio
set_servo_angle change_ownership dump_info)
RPCS = %w(_if calibrate change_ownership check_updates
config_update dump_info emergency_lock
emergency_unlock execute execute_script
factory_reset find_home home install_farmware
install_first_party_farmware move_absolute
move_relative power_off read_pin read_status
reboot register_gpio remove_farmware send_message
set_servo_angle set_user_env sync take_photo
toggle_pin unregister_gpio update_farmware wait
write_pin zero)
ALLOWED_PACKAGES = %w(farmbot_os arduino_firmware)
ALLOWED_CHAGES = %w(add remove update)
RESOURCE_NAME = %w(images plants regimens peripherals
@ -32,9 +33,6 @@ module CeleryScriptSettingsBag
ALLOWED_AXIS = %w(x y z all)
ALLOWED_LHS_TYPES = [String, :named_pin]
ALLOWED_LHS_STRINGS = [*(0..69)].map{|x| "pin#{x}"}.concat(%w(x y z))
STEPS = %w(_if execute execute_script find_home move_absolute
move_relative read_pin send_message take_photo wait
write_pin )
BAD_ALLOWED_PIN_MODES = '"%s" is not a valid pin_mode. Allowed values: %s'
BAD_LHS = 'Can not put "%s" into a left hand side (LHS) '\
'argument. Allowed values: %s'
@ -192,7 +190,7 @@ module CeleryScriptSettingsBag
.node(:send_message, [:message, :message_type], [:channel])
.node(:execute, [:sequence_id])
.node(:_if, [:lhs, :op, :rhs, :_then, :_else], [:pair])
.node(:sequence, [:version, :locals], STEPS)
.node(:sequence, [:version, :locals], RPCS)
.node(:home, [:speed, :axis], [])
.node(:find_home, [:speed, :axis], [])
.node(:zero, [:axis], [])
@ -205,7 +203,7 @@ module CeleryScriptSettingsBag
.node(:reboot, [], [])
.node(:toggle_pin, [:pin_number], [])
.node(:explanation, [:message], [])
.node(:rpc_request, [:label], ALLOWED_RPC_NODES)
.node(:rpc_request, [:label], RPCS)
.node(:rpc_ok, [:label], [])
.node(:rpc_error, [:label], [:explanation])
.node(:calibrate, [:axis], [])

View File

@ -0,0 +1,2 @@
class Permission < ApplicationRecord
end

View File

@ -55,7 +55,7 @@ class Sequence < ApplicationRecord
end
def manually_sync!
device.auto_sync_transaction { broadcast! } if device
device.auto_sync_transaction { broadcast! } if device # && !self.is_public
end
# THIS IS AN OVERRIDE - See Sequence#body_as_json

View File

@ -2,7 +2,8 @@
# expiration date).
class TokenIssuance < ApplicationRecord
belongs_to :device
after_destroy :maybe_evict_clients
puts "Fix client eviction logic."
# after_destroy :maybe_evict_clients
def broadcast?
false
@ -20,10 +21,11 @@ class TokenIssuance < ApplicationRecord
# Kick _everyone_ off the broker. The clients with the revoked token will
# not be able to reconnect.
def maybe_evict_clients
Timeout::timeout(2.5) do
id = "device_#{device_id}"
Transport::Mgmt.try(:close_connections_for_username, id)
end
puts "TODO: Fix this (slow) method."
# Timeout::timeout(Rails.env.test? ? 0.1 : 2.5) do
# id = "device_#{device_id}"
# Transport::Mgmt.try(:close_connections_for_username, id)
# end
rescue Faraday::ConnectionFailed
rescue Timeout::Error
Rollbar.error("Failed to evict clients on token revocation")

View File

@ -31,6 +31,8 @@ module Sequences
seq.manually_sync! # We must manually sync this resource.
result
end
rescue ActiveRecord::RecordInvalid
binding.pry
end
end
end

View File

@ -0,0 +1,24 @@
module Sequences
class MaybeBootstrap
PATH = File.join File.dirname(__FILE__), "public_sequences.json"
PUBLIC_SEQUENCES = JSON.parse(File.read(PATH))
def self.run!
Sequence.transaction do
public_device.save!
PUBLIC_SEQUENCES
.reject { |p| Sequence.where(is_public: true, name: p["name"]).any? }
.map { |p| p[:device] = public_device; p }
.map { |p| Sequences::Create.run!(p) }
.pluck(:id)
.map { |id| Sequence.find(id).update_attributes!(is_public: true) }
end
end
private
def self.public_device
@public_device ||= Device.find_or_create_by!(name: "Public FarmBot")
end
end
end

View File

@ -0,0 +1,38 @@
[
{
"name": "Sync",
"body": [
{
"kind": "sync",
"args": {}
}
]
},
{
"name": "E-stop",
"body": [
{
"kind": "emergency_lock",
"args": {}
}
]
},
{
"name": "Shutdown",
"body": [
{
"kind": "power_off",
"args": {}
}
]
},
{
"name": "Reboot",
"body": [
{
"kind": "reboot",
"args": {}
}
]
}
]

View File

@ -0,0 +1 @@
# Sequences::MaybeBootstrap.run!

View File

@ -1,5 +1,5 @@
class AddPublicToSequences < ActiveRecord::Migration[5.2]
def change
add_column :sequences, :public, :boolean, default: false
add_column :sequences, :is_public, :boolean, default: false
end
end

View File

@ -0,0 +1,12 @@
class CreatePermissions < ActiveRecord::Migration[5.2]
def change
create_table :permissions do |t|
t.timestamps
t.string :name, limit: 16
end
create_join_table :devices, :permissions do |t|
t.index [:device_id, :permission_id]
t.index [:permission_id, :device_id]
end
end
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2018_07_10_184108) do
ActiveRecord::Schema.define(version: 2018_07_11_143520) do
# These are extensions that must be enabled in order to support this database
enable_extension "hstore"
@ -53,6 +53,13 @@ ActiveRecord::Schema.define(version: 2018_07_10_184108) do
t.index ["timezone"], name: "index_devices_on_timezone"
end
create_table "devices_permissions", id: false, force: :cascade do |t|
t.bigint "device_id", null: false
t.bigint "permission_id", null: false
t.index ["device_id", "permission_id"], name: "index_devices_permissions_on_device_id_and_permission_id"
t.index ["permission_id", "device_id"], name: "index_devices_permissions_on_permission_id_and_device_id"
end
create_table "diagnostic_dumps", force: :cascade do |t|
t.bigint "device_id", null: false
t.string "ticket_identifier", null: false
@ -273,6 +280,12 @@ ActiveRecord::Schema.define(version: 2018_07_10_184108) do
t.index ["mode"], name: "index_peripherals_on_mode"
end
create_table "permissions", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name", limit: 16
end
create_table "pin_bindings", force: :cascade do |t|
t.bigint "device_id"
t.integer "pin_num"
@ -393,7 +406,7 @@ ActiveRecord::Schema.define(version: 2018_07_10_184108) do
t.datetime "updated_at"
t.datetime "created_at"
t.boolean "migrated_nodes", default: false
t.boolean "public", default: false
t.boolean "is_public", default: false
t.index ["created_at"], name: "index_sequences_on_created_at"
t.index ["device_id"], name: "index_sequences_on_device_id"
end

View File

@ -127,7 +127,7 @@ class CorpusEmitter
result.push(enum_type :Color, Sequence::COLORS)
result.push(enum_type :LegalArgString, HASH[:args].map{ |x| x[:name] }.sort.uniq)
result.push(enum_type :LegalKindString, HASH[:nodes].map{ |x| x[:name] }.sort.uniq)
result.push(enum_type :LegalSequenceKind, CeleryScriptSettingsBag::STEPS.sort)
result.push(enum_type :LegalSequenceKind, CeleryScriptSettingsBag::RPCS.sort)
result.push(enum_type :DataChangeType, CeleryScriptSettingsBag::ALLOWED_CHAGES)
result.push(enum_type :PointType, CeleryScriptSettingsBag::ALLOWED_POINTER_TYPE)
result.push(enum_type :AllowedPinTypes, CeleryScriptSettingsBag::ALLOWED_PIN_TYPES)

View File

@ -0,0 +1,5 @@
FactoryBot.define do
factory :permission do
end
end

View File

@ -0,0 +1,5 @@
require 'spec_helper'
RSpec.describe Permission, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -9,8 +9,8 @@ describe TokenIssuance do
end
it "clears out old stuff via #clean_old_tokens" do
TokenIssuance.delete_all
TokenIssuance.create(device_id: 8,
TokenIssuance.destroy_all
TokenIssuance.create(device_id: FactoryBot.create(:device).id,
exp: 1.year.ago.to_i,
jti: "WOW")
expect(TokenIssuance.count).to eq(1)

View File

@ -0,0 +1,19 @@
require "spec_helper"
describe Sequences::MaybeBootstrap do
it "bootstraps a list of public sequences (only once)" do
Point.destroy_all
TokenIssuance.destroy_all
Device.destroy_all
Sequence.destroy_all
ps = Sequences::MaybeBootstrap::PUBLIC_SEQUENCES
Sequences::MaybeBootstrap.run!
expect(Device.count).to eq(1)
expect(Sequence.count).to eq(ps.count)
Sequences::MaybeBootstrap.run!
expect(Device.count).to eq(1)
expect(Sequence.count).to eq(ps.count)
end
end