Backend utils for broadcasting
parent
e3abb4bf6a
commit
35b9c145c6
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue