Backend utils for broadcasting

pull/1166/head
Rick Carlino 2019-04-19 14:07:47 -07:00
parent e3abb4bf6a
commit 35b9c145c6
4 changed files with 109 additions and 33 deletions

View File

@ -1,5 +1,5 @@
class GlobalBulletin < ActiveRecord::Base
class GlobalBulletin < ActiveRecord::Base
self.inheritance_column = "none"
validates_uniqueness_of :slug
validates_presence_of :content, :href, :slug, :type
validates_presence_of :content, :slug, :type
end

View File

@ -625,6 +625,7 @@ ALTER SEQUENCE public.fragments_id_seq OWNED BY public.fragments.id;
CREATE TABLE public.global_bulletins (
id bigint NOT NULL,
href character varying,
href_label character varying,
slug character varying,
title character varying,
type character varying,

View File

@ -8,10 +8,10 @@ def check_for_digests
.pluck(:device_id)
.uniq
.map do |id|
device = Device.find(id)
puts "Sending log digest to device \##{id} (#{device.name})"
LogDeliveryMailer.log_digest(device).deliver
end
device = Device.find(id)
puts "Sending log digest to device \##{id} (#{device.name})"
LogDeliveryMailer.log_digest(device).deliver
end
sleep 10.minutes
end
@ -38,7 +38,7 @@ def user_typed?(word)
end
namespace :api do
desc "Runs pending email digests. "\
desc "Runs pending email digests. " \
"Use the `FOREVER` ENV var to continually check."
task log_digest: :environment do
puts "Running log digest loop..."
@ -51,14 +51,13 @@ namespace :api do
end
def parcel(cmd, opts = " ")
intro = [ "node_modules/parcel-bundler/bin/cli.js",
cmd,
DashboardController::PARCEL_ASSET_LIST,
"--out-dir",
DashboardController::PUBLIC_OUTPUT_DIR,
"--public-url",
DashboardController::OUTPUT_URL,
].join(" ")
intro = ["node_modules/parcel-bundler/bin/cli.js",
cmd,
DashboardController::PARCEL_ASSET_LIST,
"--out-dir",
DashboardController::PUBLIC_OUTPUT_DIR,
"--public-url",
DashboardController::OUTPUT_URL].join(" ")
sh [intro, opts].join(" ")
end
@ -67,8 +66,7 @@ namespace :api do
# Clear out cache and previous builds on initial load.
sh ["rm -rf",
DashboardController::CACHE_DIR,
DashboardController::PUBLIC_OUTPUT_DIR
].join(" ")
DashboardController::PUBLIC_OUTPUT_DIR].join(" ")
parcel "watch", DashboardController::PARCEL_HMR_OPTS
end
@ -79,7 +77,7 @@ namespace :api do
desc "Reset _everything_, including your database"
task :reset do
puts "This is going to destroy _ALL_ of your local Farmbot SQL data and "\
puts "This is going to destroy _ALL_ of your local Farmbot SQL data and " \
"configs. Type 'destroy' to continue, enter to abort."
if user_typed?("destroy")
hard_reset_api
@ -88,38 +86,38 @@ namespace :api do
end
end
VERSION = "tag_name"
VERSION = "tag_name"
TIMESTAMP = "created_at"
desc "Update GlobalConfig to deprecate old FBOS versions"
task deprecate: :environment do
# Get current version
version_str = GlobalConfig.dump.fetch("FBOS_END_OF_LIFE_VERSION")
version_str = GlobalConfig.dump.fetch("FBOS_END_OF_LIFE_VERSION")
# Convert it to Gem::Version for easy comparisons (>, <, ==, etc)
current_version = Gem::Version::new(version_str)
# 60 days is the current policy.
cutoff = 60.days.ago
cutoff = 60.days.ago
# Download release data from github
stringio = open("https://api.github.com/repos/farmbot/farmbot_os/releases")
string = stringio.read
data = JSON
.parse(string)
.map { |x| x.slice(VERSION, TIMESTAMP) } # Only grab keys that matter
.reject { |x| x.fetch(VERSION).include?("-") } # Remove RC/Beta releases
.map do |x|
string = stringio.read
data = JSON
.parse(string)
.map { |x| x.slice(VERSION, TIMESTAMP) } # Only grab keys that matter
.reject { |x| x.fetch(VERSION).include?("-") } # Remove RC/Beta releases
.map do |x|
# Convert string-y version/timestamps to Real ObjectsTM
version = Gem::Version::new(x.fetch(VERSION).gsub("v", ""))
time = DateTime.parse(x.fetch(TIMESTAMP))
time = DateTime.parse(x.fetch(TIMESTAMP))
Pair.new(version, time)
end
.select do |pair|
.select do |pair|
# Grab versions that are > current version and outside of cutoff window
(pair.head > current_version) && (pair.tail < cutoff)
end
.sort_by { |p| p.tail } # Sort by release date
.last(2) # Grab 2 latest versions (closest to cuttof)
.first # Give 'em some leeway, grabbing the 2nd most outdated version.
.try(:head) # We might already be up-to-date?
.sort_by { |p| p.tail } # Sort by release date
.last(2) # Grab 2 latest versions (closest to cuttof)
.first # Give 'em some leeway, grabbing the 2nd most outdated version.
.try(:head) # We might already be up-to-date?
if data # ...or not
puts "Setting new support target to #{data.to_s}"
GlobalConfig # Set the new oldest support version.

View File

@ -0,0 +1,77 @@
class BroadcastToAll < Mutations::Command
RELEVANT_TIMEFRAME = 7.months.ago
required do
string :title
string :content
end
optional do
string :type, default: "info"
string :href
string :href_label
end
def execute
create_bulletin
attach_alerts
end
def create_bulletin
@bulletin ||= GlobalBulletin.create!(title: title,
type: type,
content: content,
slug: slug,
href: href,
href_label: href_label)
end
def slug
@slug ||= title.parameterize
end
def devices
@devices ||= Device.where("updated_at > ?", RELEVANT_TIMEFRAME)
end
def attach_alerts
puts "This will take a while..."
devices.map do |d|
puts "attaching Alert to Device #{d.id}"
Alerts::Create.run!(problem_tag: Alert::BULLETIN,
device: d,
slug: slug)
end
end
end
def prompt(query)
puts "=== #{query}"
output = STDIN.gets.chomp
output.length == 0 ? nil : output
end
def mutliline_prompt(query)
puts "=== #{query}"
puts "TYPE @@@ TO FINISH"
buffer = []
loop {
chunk = STDIN.gets.chomp
break if chunk == "@@@" # Just to show one example for a break condition here
buffer.push(chunk)
}
buffer.length == 0 ? nil : buffer.join("\n")
end
namespace :broadcast do
desc "Create a global bulletin for all users"
task to_all: :environment do
puts "BEGIN"
BroadcastToAll.run!(type: prompt("(optional) Enter `type`"),
href: prompt("(optional) Enter href"),
href_label: prompt("(optional) Enter href label"),
title: prompt("Enter title"),
content: mutliline_prompt("Enter content"))
puts "DONE"
end
end