Merge branch 'staging' into issue-1582

pull/1636/head
Fabio Dessi 2019-12-20 16:17:49 +01:00
commit 98a0abd7fa
24 changed files with 177 additions and 25 deletions

View File

@ -12,6 +12,7 @@ module Devices
time :last_saw_mq
time :last_ota
time :last_ota_checkup
boolean :needs_reset
integer :mounted_tool_id, nils: true
integer :ota_hour, nils: true
end

View File

@ -10,13 +10,14 @@ module SensorReadings
end
optional do
time :read_at
integer :mode,
in: CeleryScriptSettingsBag::ALLOWED_PIN_MODES,
default: CeleryScriptSettingsBag::DIGITAL
end
def execute
SensorReading.create!(inputs)
SensorReading.create!(inputs.merge(read_at: read_at || Time.now))
end
end
end

View File

@ -6,6 +6,7 @@ class DeviceSerializer < ApplicationSerializer
:last_saw_mq,
:mounted_tool_id,
:name,
:needs_reset,
:ota_hour,
:serial_number,
:throttled_at,

View File

@ -1,3 +1,10 @@
class SensorReadingSerializer < ApplicationSerializer
attributes :mode, :pin, :value, :x, :y, :z
attributes :mode, :pin, :value, :x, :y, :z, :read_at
# This is for legacy support reasons.
# Very old sensor_readings will have a
# read_at value of `nil`, so we pre-populate it
# to `created_at` for the convinience of API users.
def read_at
object.read_at || object.created_at
end
end

View File

@ -0,0 +1,8 @@
class AddNeedsResetToDevices < ActiveRecord::Migration[6.0]
def change
add_column :devices,
:needs_reset,
:boolean,
default: false
end
end

View File

@ -0,0 +1,5 @@
class AddReadAtToSensorReadings < ActiveRecord::Migration[6.0]
def change
add_column :sensor_readings, :read_at, :datetime, default: nil
end
end

View File

@ -276,7 +276,8 @@ CREATE TABLE public.devices (
mqtt_rate_limit_email_sent_at timestamp without time zone,
last_ota timestamp without time zone,
last_ota_checkup timestamp without time zone,
ota_hour integer DEFAULT 3
ota_hour integer DEFAULT 3,
needs_reset boolean DEFAULT false
);
@ -663,6 +664,40 @@ CREATE SEQUENCE public.firmware_configs_id_seq
ALTER SEQUENCE public.firmware_configs_id_seq OWNED BY public.firmware_configs.id;
--
-- Name: folders; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.folders (
id bigint NOT NULL,
device_id bigint NOT NULL,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
color character varying(20) NOT NULL,
name character varying(40) NOT NULL,
parent_id integer
);
--
-- Name: folders_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.folders_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: folders_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.folders_id_seq OWNED BY public.folders.id;
--
-- Name: fragments; Type: TABLE; Schema: public; Owner: -
--
@ -841,7 +876,8 @@ CREATE TABLE public.sequences (
kind character varying(280) DEFAULT 'sequence'::character varying,
updated_at timestamp without time zone,
created_at timestamp without time zone,
migrated_nodes boolean DEFAULT false
migrated_nodes boolean DEFAULT false,
folder_id bigint
);
@ -1370,7 +1406,7 @@ CREATE VIEW public.resource_update_steps AS
edge_nodes.kind,
edge_nodes.value
FROM public.edge_nodes
WHERE (((edge_nodes.kind)::text = 'resource_type'::text) AND ((edge_nodes.value)::text = ANY ((ARRAY['"GenericPointer"'::character varying, '"ToolSlot"'::character varying, '"Plant"'::character varying])::text[])))
WHERE (((edge_nodes.kind)::text = 'resource_type'::text) AND ((edge_nodes.value)::text = ANY (ARRAY[('"GenericPointer"'::character varying)::text, ('"ToolSlot"'::character varying)::text, ('"Plant"'::character varying)::text])))
), resource_id AS (
SELECT edge_nodes.primary_node_id,
edge_nodes.kind,
@ -1447,7 +1483,8 @@ CREATE TABLE public.sensor_readings (
pin integer,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
mode integer DEFAULT 0
mode integer DEFAULT 0,
read_at timestamp without time zone
);
@ -1649,7 +1686,8 @@ CREATE TABLE public.users (
agreed_to_terms_at timestamp without time zone,
confirmation_sent_at timestamp without time zone,
unconfirmed_email character varying,
inactivity_warning_sent_at timestamp without time zone
inactivity_warning_sent_at timestamp without time zone,
inactivity_warning_count integer
);
@ -1887,6 +1925,13 @@ ALTER TABLE ONLY public.fbos_configs ALTER COLUMN id SET DEFAULT nextval('public
ALTER TABLE ONLY public.firmware_configs ALTER COLUMN id SET DEFAULT nextval('public.firmware_configs_id_seq'::regclass);
--
-- Name: folders id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.folders ALTER COLUMN id SET DEFAULT nextval('public.folders_id_seq'::regclass);
--
-- Name: fragments id; Type: DEFAULT; Schema: public; Owner: -
--
@ -2203,6 +2248,14 @@ ALTER TABLE ONLY public.firmware_configs
ADD CONSTRAINT firmware_configs_pkey PRIMARY KEY (id);
--
-- Name: folders folders_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.folders
ADD CONSTRAINT folders_pkey PRIMARY KEY (id);
--
-- Name: fragments fragments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -2575,6 +2628,13 @@ CREATE INDEX index_fbos_configs_on_device_id ON public.fbos_configs USING btree
CREATE INDEX index_firmware_configs_on_device_id ON public.firmware_configs USING btree (device_id);
--
-- Name: index_folders_on_device_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_folders_on_device_id ON public.folders USING btree (device_id);
--
-- Name: index_fragments_on_device_id; Type: INDEX; Schema: public; Owner: -
--
@ -2904,6 +2964,13 @@ CREATE INDEX index_sequences_on_created_at ON public.sequences USING btree (crea
CREATE INDEX index_sequences_on_device_id ON public.sequences USING btree (device_id);
--
-- Name: index_sequences_on_folder_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_sequences_on_folder_id ON public.sequences USING btree (folder_id);
--
-- Name: index_standard_pairs_on_arg_name_id; Type: INDEX; Schema: public; Owner: -
--
@ -3026,6 +3093,14 @@ ALTER TABLE ONLY public.pin_bindings
ADD CONSTRAINT fk_rails_1f1c3b6979 FOREIGN KEY (device_id) REFERENCES public.devices(id);
--
-- Name: folders fk_rails_58e285f76e; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.folders
ADD CONSTRAINT fk_rails_58e285f76e FOREIGN KEY (parent_id) REFERENCES public.folders(id);
--
-- Name: sensors fk_rails_92e56bf2fb; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@ -3368,6 +3443,9 @@ INSERT INTO "schema_migrations" (version) VALUES
('20190930202839'),
('20191002125625'),
('20191107170431'),
('20191119204916');
('20191119204916'),
('20191203163621'),
('20191219212755'),
('20191220010646');

View File

@ -47,6 +47,7 @@ export function fakeSequence(): TaggedSequence {
color: "red",
name: "fake",
kind: "sequence",
folder_id: undefined,
body: []
});
}
@ -228,6 +229,7 @@ export function fakeSensorReading(): TaggedSensorReading {
return fakeResource("SensorReading", {
id: idCounter++,
created_at: "2018-01-11T20:20:38.362Z",
read_at: "2018-01-11T20:20:38.362Z",
pin: 1,
value: 0,
mode: 0,

View File

@ -39,6 +39,7 @@ const tr0: TaggedResource = {
"id": 23,
"name": "Goto 0, 0, 0",
"color": "gray",
"folder_id": undefined,
"body": [
{
"kind": "move_absolute",
@ -366,6 +367,7 @@ const KIND_PRIORITY: ResourceLookupTable = {
Sensor: 1,
Tool: 1,
Alert: 1,
Folder: 1,
PointGroup: 2,
SensorReading: 2,
Sequence: 2,
@ -400,6 +402,7 @@ const blankSeq: TaggedSequence = {
"body": {
"id": undefined,
"name": "Repair sequence",
"folder_id": undefined,
"color": "gray",
"body": [],
"args": {

View File

@ -39,6 +39,7 @@ describe("commitBulkEditor()", () => {
id: sequence_id,
name: "Test Sequence",
color: "gray",
folder_id: undefined,
body: [{ kind: "wait", args: { milliseconds: 100 } }],
args: { "locals": { kind: "scope_declaration", args: {} }, "version": 4 },
kind: "sequence"

View File

@ -108,6 +108,7 @@ describe("in_use tracking at reducer level", () => {
name: "Y",
kind: "sequence",
color: "blue",
folder_id: undefined,
args: { version: 8, locals: { kind: "scope_declaration", args: {} } }
})[0];
sequence.body.id = sequence_id;

View File

@ -27,6 +27,7 @@ describe("resource reducer", () => {
const next = resourceReducer(state, overwrite(sequence, {
kind: "sequence",
name: "wow",
folder_id: undefined,
args: { version: -0, locals: { kind: "scope_declaration", args: {} } },
body: [],
color: "red"

View File

@ -10,6 +10,7 @@ describe("tagAllSteps()", () => {
"body": {
"id": 8,
"name": "Goto 0, 0, 0",
"folder_id": undefined,
"color": "gray",
"body": [
{

View File

@ -63,6 +63,7 @@ export const emptyState = (): RestResources => {
User: {},
WebAppConfig: {},
WebcamFeed: {},
Folder: {}
},
byKindAndId: {},
references: {},

View File

@ -15,6 +15,7 @@ describe("<AllSteps/>", () => {
"body": sanitizeNodes({
"id": 8,
"name": "Goto 0, 0, 0",
"folder_id": undefined,
"color": "gray",
"body": [
{

View File

@ -36,6 +36,7 @@ describe("<TestButton/>", () => {
"name": "Goto 0, 0, 0",
"color": "gray",
"body": [],
"folder_id": undefined,
"args": {
"version": 4,
"locals": { kind: "scope_declaration", args: {} },

View File

@ -40,6 +40,7 @@ describe("<InputDefault/>", () => {
"name": "Goto 0, 0, 0",
"color": "gray",
"body": [step],
"folder_id": undefined,
"args": {
"version": 4,
"locals": { kind: "scope_declaration", args: {} },

View File

@ -91,6 +91,7 @@ const SequenceListItem = (props: SequenceListItemProps) =>
const emptySequenceBody = (seqCount: number): TaggedSequence["body"] => ({
name: t("new sequence {{ num }}", { num: seqCount }),
folder_id: undefined,
args: {
version: -999,
locals: { kind: "scope_declaration", args: {} },

View File

@ -39,6 +39,7 @@ const seedSequence: TaggedSequence = {
color: "red",
name: "test",
kind: "sequence",
folder_id: undefined,
args: {
locals: { kind: "scope_declaration", args: {} },
version: 9999

View File

@ -24,18 +24,18 @@
"author": "farmbot.io",
"license": "MIT",
"dependencies": {
"@babel/core": "7.7.4",
"@blueprintjs/core": "3.22.0",
"@babel/core": "7.7.5",
"@blueprintjs/core": "3.22.2",
"@blueprintjs/datetime": "3.15.1",
"@blueprintjs/select": "3.11.2",
"@types/enzyme": "3.10.3",
"@types/enzyme": "3.10.4",
"@types/jest": "24.0.23",
"@types/lodash": "4.14.149",
"@types/markdown-it": "0.0.9",
"@types/moxios": "0.4.9",
"@types/node": "12.12.14",
"@types/node": "12.12.17",
"@types/promise-timeout": "1.3.0",
"@types/react": "16.9.14",
"@types/react": "16.9.16",
"@types/react-color": "3.0.1",
"@types/react-dom": "16.9.4",
"@types/react-redux": "7.1.5",
@ -45,8 +45,8 @@
"coveralls": "3.0.9",
"enzyme": "3.10.0",
"enzyme-adapter-react-16": "1.15.1",
"farmbot": "8.3.1",
"i18next": "19.0.1",
"farmbot": "9.0.0",
"i18next": "19.0.2",
"install": "0.13.0",
"lodash": "4.17.15",
"markdown-it": "10.0.0",
@ -54,7 +54,7 @@
"moment": "2.24.0",
"moxios": "0.4.0",
"mqtt": "3.0.0",
"npm": "6.13.1",
"npm": "6.13.4",
"parcel-bundler": "1.12.4",
"promise-timeout": "1.3.0",
"raf": "3.4.1",
@ -75,14 +75,14 @@
"ts-jest": "24.2.0",
"ts-lint": "4.5.1",
"tslint": "5.20.1",
"typescript": "3.7.2",
"typescript": "3.7.3",
"which": "2.0.2"
},
"devDependencies": {
"jest": "24.9.0",
"jest-cli": "24.9.0",
"jest-skipped-reporter": "0.0.5",
"jshint": "2.10.3",
"jshint": "2.11.0-rc1",
"madge": "3.6.0"
},
"jest": {

View File

@ -7,11 +7,39 @@ describe Api::SensorReadingsController do
let(:user) { FactoryBot.create(:user) }
let (:reading) { FactoryBot.create(:sensor_reading, device: user.device) }
it "sets a default `read_at` value" do
sign_in user
before = SensorReading.count
read_at = Time.now - 5.hours
post :create,
body: {
pin: 13,
value: 128,
x: nil,
y: 1,
z: 2,
mode: 1
}.to_json,
params: { format: :json }
expect(response.status).to eq(200)
expect(json[:created_at]).to eq(json[:read_at])
end
it "makes a sensor reading" do
sign_in user
before = SensorReading.count
read_at = Time.now - 5.hours
post :create,
body: { pin: 13, value: 128, x: nil, y: 1, z: 2, mode: 1 }.to_json,
body: {
pin: 13,
value: 128,
x: nil,
y: 1,
z: 2,
mode: 1,
read_at: read_at
}.to_json,
params: { format: :json }
expect(response.status).to eq(200)
@ -24,6 +52,7 @@ describe Api::SensorReadingsController do
expect(json[:z]).to eq(2)
expect(json[:pin]).to eq(13)
expect(json[:mode]).to eq(1)
expect(read_at.as_json.first(23)).to eq(json[:read_at].first(23))
expect(before < SensorReading.count).to be_truthy
end

View File

@ -10,13 +10,17 @@ describe DashboardController do
expect(response.status).to eq(200)
end
it "renders the terms of service" do
it "renders the front page" do
get :front_page
expect(response.status).to eq(200)
# first entry in api_docs.md
SmarfDoc.note("Documentation generated for the " +
"[FarmBot Web App](https://github.com/FarmBot/Farmbot-Web-App).")
end
it "renders the terms of service" do
expect { get :main_app, params: { path: "nope.jpg" } }.to raise_error(ActionController::RoutingError)
it "returns error on invalid path" do
expect { get :main_app, params: { path: "nope.jpg" } }
.to raise_error(ActionController::RoutingError)
end
it "receives CSP violation reports (malformed JSON)" do
@ -26,7 +30,7 @@ describe DashboardController do
expect(json).to eq(problem: "Crashed while parsing report")
end
it "receives CSP violation reports (malformed JSON)" do
it "receives CSP violation reports (JSON)" do
post :csp_reports, body: {}.to_json, params: { format: :json }
expect(json).to eq({})
end

View File

@ -7,10 +7,11 @@ describe Devices::Update do
it 'updates an existing device' do
previous_name = device.name
p = { last_saw_mq: Time.now.utc, name: "Farmbot" }
p = { last_saw_mq: Time.now.utc, name: "Farmbot", needs_reset: true }
Devices::Update.run!({device: device}, p)
device.reload
expect(device.name).to eq(p[:name])
expect(device.needs_reset).to eq(p[:needs_reset])
expect(device.last_saw_mq.hour).to eq(p[:last_saw_mq].hour)
expect(device.last_saw_mq.min).to eq(p[:last_saw_mq].min)
end

View File

@ -83,7 +83,9 @@ RSpec.configure do |config|
config.order = "random"
if ENV["DOCS"]
config.after(:each, type: :controller) do
SmarfDoc.run!(NiceResponse.new(request), response)
if request.path.length > 0 || response.body.length > 0
SmarfDoc.run!(NiceResponse.new(request), response)
end
end
config.after(:suite) do