Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.4.3
3.4.4
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
source "https://rubygems.org"
ruby "~> 3.4.3"
ruby "~> 3.4.4"

gem "rails", "~> 6"
gem "active_model_serializers"
Expand Down
8 changes: 4 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ GEM
google-cloud-core (1.8.0)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (2.3.0)
google-cloud-env (2.3.1)
base64 (~> 0.2)
faraday (>= 1.0, < 3.a)
google-cloud-errors (1.5.0)
Expand Down Expand Up @@ -173,7 +173,7 @@ GEM
mutex_m
i18n (1.14.7)
concurrent-ruby (~> 1.0)
json (2.12.0)
json (2.12.2)
jsonapi-renderer (0.2.2)
jwt (2.10.1)
base64
Expand Down Expand Up @@ -380,7 +380,7 @@ GEM
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webrick (1.9.1)
websocket-driver (0.7.7)
websocket-driver (0.8.0)
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
Expand Down Expand Up @@ -438,7 +438,7 @@ DEPENDENCIES
webmock

RUBY VERSION
ruby 3.4.3p32
ruby 3.4.4p34

BUNDLED WITH
2.6.9
7 changes: 5 additions & 2 deletions app/controllers/api/images_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module Api
# 3. Image is transferred to the "trusted bucket".
class ImagesController < Api::AbstractController
cattr_accessor :store_locally
self.store_locally = !ENV["GCS_BUCKET"]

def create
mutate Images::Create.run(raw_json, device: current_device)
Expand All @@ -32,8 +31,12 @@ def storage_auth

private

def self.store_locally?
!ENV["GCS_BUCKET"]
end

def policy_class
if ImagesController.store_locally
if ImagesController.store_locally?
Images::StubPolicy
else
Images::GeneratePolicy
Expand Down
26 changes: 13 additions & 13 deletions app/models/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,23 @@ def set_defaults
CONFIG = { default_url: DEFAULT_URL,
styles: RMAGICK_STYLES,
size: { in: 0..MAX_IMAGE_SIZE } }
BUCKET = ENV["GCS_BUCKET"]

ROOT_PATH = BUCKET ?
"https://#{BUCKET}.storage.googleapis.com" : "/system"
IMAGE_URL_TPL =
ROOT_PATH + "/images/attachments/%{chunks}/%{size}/%{filename}?%{timestamp}"

CONTENT_TYPES = ["image/jpg", "image/jpeg", "image/png", "image/gif"]
GCS_ACCESS_KEY_ID = ENV.fetch("GCS_KEY") { puts "Not using Google Cloud" }
GCS_HOST = "http://#{BUCKET}.storage.googleapis.com"
GCS_SECRET_ACCESS_KEY = ENV.fetch("GCS_ID") { puts "Not using Google Cloud" }
# Worst case scenario for 1280x1280 BMP.
GCS_BUCKET_NAME = ENV["GCS_BUCKET"]

has_one_attached :attachment

def bucket
ENV["GCS_BUCKET"]
end

def image_url_tpl
root_path = bucket ? "https://#{bucket}.storage.googleapis.com" : "/system"
root_path + "/images/attachments/%{chunks}/%{size}/%{filename}?%{timestamp}"
end

def set_attachment_by_url(url)
io = URI.parse(url).open
fname = "image_#{self.id}"
Expand Down Expand Up @@ -73,9 +74,8 @@ def regular_image?
end

def regular_url
if BUCKET
# Not sure why. TODO: Investigate why Rails URL helpers don't work here.
"https://storage.googleapis.com/#{BUCKET}/#{attachment.key}"
if bucket
"https://storage.googleapis.com/#{bucket}/#{attachment.key}"
else
Rails
.application
Expand All @@ -86,7 +86,7 @@ def regular_url
end

def legacy_url(size)
url = IMAGE_URL_TPL % {
url = image_url_tpl % {
chunks: id.to_s.rjust(9, "0").scan(/.{3}/).join("/"),
filename: attachment_file_name,
size: size,
Expand All @@ -108,7 +108,7 @@ def attachment_url(size = "x640")
end

def self.self_hosted_image_upload(key:, file:)
raise "No." unless Api::ImagesController.store_locally
raise "No." unless Api::ImagesController.store_locally?
name = key.split("/").last
src = file.tempfile.path
dest = File.join("public", "direct_upload", "temp", name)
Expand Down
20 changes: 13 additions & 7 deletions app/mutations/images/generate_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@

module Images
class GeneratePolicy < Mutations::Command
BUCKET_NAME = ENV.fetch("GCS_BUCKET") { "YOU_MUST_CONFIG_GOOGLE_CLOUD_STORAGE" }
JSON_KEY = ENV["GOOGLE_CLOUD_KEYFILE_JSON"]
BUCKET = JSON_KEY && Google::Cloud::Storage.new.bucket(BUCKET_NAME)
HMM = "GCS NOT SETUP!"
# # Is there a better way to reach in and grab the ActiveStorage configs?
# CONFIG = YAML.load(ERB.new(File.read("config/storage.yml")).result(binding)).fetch("google")

def execute
{
verb: "POST",
url: "//storage.googleapis.com/#{BUCKET_NAME || HMM}/",
url: "//storage.googleapis.com/#{bucket_name || HMM}/",
form_data: {
"key" => file_path,
"acl" => "public-read",
Expand All @@ -31,16 +28,25 @@ def execute

private

def bucket_name
ENV["GCS_BUCKET"]
end

def bucket
json_key = ENV["GOOGLE_CLOUD_KEYFILE_JSON"]
json_key && Google::Cloud::Storage.new.bucket(bucket_name)
end

def post_object
@post_object ||= BUCKET ?
BUCKET.post_object(file_path, policy: policy).fields : {}
@post_object ||= bucket ?
bucket.post_object(file_path, policy: policy).fields : {}
end

def policy
@policy ||= {
expiration: (Time.now + 1.hour).utc.xmlschema,
conditions: [
{ bucket: BUCKET_NAME },
{ bucket: bucket_name },
{ key: file_path },
{ acl: "public-read" },
[:eq, "$Content-Type", "image/jpeg"],
Expand Down
6 changes: 2 additions & 4 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require File.expand_path("../boot", __FILE__)
require_relative "../app/lib/celery_script/cs_heap"
require "rails/all"
require_relative "./config_helpers/active_storage"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Expand All @@ -12,8 +13,6 @@ class Application < Rails::Application
Delayed::Worker.max_attempts = 4
REDIS_ENV_KEY = ENV.fetch("WHERE_IS_REDIS_URL", "REDIS_URL")
REDIS_URL = ENV.fetch(REDIS_ENV_KEY, "redis://redis:6379/0")
gcs_enabled =
%w[ GOOGLE_CLOUD_KEYFILE_JSON GCS_PROJECT GCS_BUCKET ].all? { |s| ENV.key? s }
config.lograge.enabled = true
config.lograge.ignore_actions = [
"Api::RmqUtilsController#user_action",
Expand All @@ -22,8 +21,7 @@ class Application < Rails::Application
"Api::RmqUtilsController#topic_action",
]
config.load_defaults 6.0
config.active_storage.service = gcs_enabled ?
:google : :local
config.active_storage.service = ConfigHelpers::ActiveStorage.service
config.cache_store = :redis_cache_store, { url: REDIS_URL, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }
config.middleware.use Rack::Attack
config.active_record.schema_format = :sql
Expand Down
13 changes: 13 additions & 0 deletions config/config_helpers/active_storage.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module ConfigHelpers
module ActiveStorage
REQUIRED_KEYS = %w[
GOOGLE_CLOUD_KEYFILE_JSON
GCS_PROJECT
GCS_BUCKET
].freeze

def self.service
REQUIRED_KEYS.all? { |key| ENV.key?(key) } ? :google : :local
end
end
end
2 changes: 1 addition & 1 deletion docker_configs/api.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ruby:3.4.3
FROM ruby:3.4.4
RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg > /dev/null && \
sh -c '. /etc/os-release; echo $VERSION_CODENAME; echo "deb http://apt.postgresql.org/pub/repos/apt/ $VERSION_CODENAME-pgdg main" >> /etc/apt/sources.list.d/pgdg.list' && \
apt-get update -qq && apt-get install -y build-essential libpq-dev postgresql postgresql-contrib && \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,10 @@ describe("<Tools />", () => {
toolSlot4.body.pullout_direction = ToolPulloutDirection.NEGATIVE_Y;
const toolSlot5 = fakeToolSlot();
toolSlot5.body.tool_id = tool5.body.id;
toolSlot5.body.gantry_mounted = true;
const toolSlot6 = fakeToolSlot();
toolSlot6.body.tool_id = tool6.body.id;
toolSlot6.body.gantry_mounted = true;
p.toolSlots = [
{ toolSlot: toolSlot0, tool: tool0 },
{ toolSlot: toolSlot1, tool: tool1 },
Expand Down
3 changes: 3 additions & 0 deletions frontend/three_d_garden/bot/components/tools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ interface ConvertedTools {
toolName: string | undefined;
toolPulloutDirection: ToolPulloutDirection;
firstTrough?: boolean;
gantryMounted?: boolean;
}

export const convertSlotsWithTools =
Expand All @@ -98,6 +99,7 @@ export const convertSlotsWithTools =
toolName,
toolPulloutDirection: swt.toolSlot.body.pullout_direction,
firstTrough: troughIndex < 2,
gantryMounted: swt.toolSlot.body.gantry_mounted,
};
});
};
Expand Down Expand Up @@ -423,6 +425,7 @@ export const Tools = (props: ToolsProps) => {
{tools.map((tool, i) =>
<Tool key={i}
{...tool}
x={tool.gantryMounted ? botPosition.x : tool.x}
inToolbay={true} />)}
</Group>;
};
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
"@blueprintjs/core": "5.19.0",
"@blueprintjs/select": "5.3.20",
"@monaco-editor/react": "4.7.0",
"@parcel/transformer-sass": "2.15.1",
"@parcel/transformer-typescript-tsc": "2.15.1",
"@parcel/transformer-sass": "2.15.2",
"@parcel/transformer-typescript-tsc": "2.15.2",
"@react-spring/three": "10.0.1",
"@react-three/drei": "9.122.0",
"@react-three/fiber": "8.18.0",
Expand All @@ -62,15 +62,15 @@
"delaunator": "5.0.1",
"events": "3.3.0",
"farmbot": "15.8.11",
"i18next": "25.2.0",
"i18next": "25.2.1",
"lodash": "4.17.21",
"markdown-it": "14.1.0",
"markdown-it-emoji": "3.0.0",
"moment": "2.30.1",
"monaco-editor": "0.52.2",
"mqtt": "5.13.0",
"npm": "11.4.1",
"parcel": "2.15.1",
"parcel": "2.15.2",
"process": "0.11.10",
"promise-timeout": "1.3.0",
"punycode": "1.4.1",
Expand All @@ -79,7 +79,7 @@
"react-color": "2.19.3",
"react-dom": "18.3.1",
"react-redux": "9.2.0",
"react-router": "7.6.0",
"react-router": "7.6.1",
"redux": "5.0.1",
"redux-immutable-state-invariant": "2.1.0",
"redux-thunk": "3.1.0",
Expand Down
23 changes: 23 additions & 0 deletions spec/config_helpers/active_storage_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require "spec_helper"

describe ConfigHelpers::ActiveStorage do
it "returns :google when all required env vars are set" do
with_modified_env(
GOOGLE_CLOUD_KEYFILE_JSON: "key",
GCS_PROJECT: "project",
GCS_BUCKET: "bucket",
) do
expect(described_class.service).to eq(:google)
end
end

it "returns :local when no required env vars are set" do
with_modified_env(
GOOGLE_CLOUD_KEYFILE_JSON: nil,
GCS_PROJECT: nil,
GCS_BUCKET: nil,
) do
expect(described_class.service).to eq(:local)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
describe "#create" do
it "creates a new FarmwareInstallation" do
sign_in user
url = Faker::Internet.url host: "example.com", path: "/#{SecureRandom.hex(16)}/manifest.json"
hex = SecureRandom.hex(16)
url = Faker::Internet.url host: "example.com", path: "/#{hex}/manifest.json"
stub_request(:get, url).to_return(status: 200, body: "", headers: {})
payload = { url: url }
old_installation_count = FarmwareInstallation.count
post :create, body: payload.to_json, params: { format: :json }
Expand Down
Loading