diff --git a/app/controllers/v0/application_controller.rb b/app/controllers/v0/application_controller.rb index 4498e915..5e1547ed 100644 --- a/app/controllers/v0/application_controller.rb +++ b/app/controllers/v0/application_controller.rb @@ -15,6 +15,9 @@ class ApplicationController < ActionController::API helper ::UserHelper include ::UserHelper + helper ::PresentationHelper + include ::PresentationHelper + respond_to :json before_action :prepend_view_paths diff --git a/app/controllers/v0/me_controller.rb b/app/controllers/v0/me_controller.rb index f11616ea..f235edb1 100644 --- a/app/controllers/v0/me_controller.rb +++ b/app/controllers/v0/me_controller.rb @@ -39,8 +39,6 @@ def user_params :country_code, :profile_picture, :url, - :avatar, - :avatar_url ) end diff --git a/app/controllers/v0/static_controller.rb b/app/controllers/v0/static_controller.rb index b9d24667..c64e923b 100644 --- a/app/controllers/v0/static_controller.rb +++ b/app/controllers/v0/static_controller.rb @@ -116,7 +116,6 @@ def search h['url'] = v0_device_url(s.searchable_id) elsif s.searchable_type == 'User' h['username'] = s.searchable.username - h['avatar'] = s.searchable.avatar h['profile_picture'] = profile_picture_url(s.searchable) h['city'] = s.searchable.city h['url'] = v0_user_url(s.searchable_id) diff --git a/app/controllers/v0/uploads_controller.rb b/app/controllers/v0/uploads_controller.rb deleted file mode 100644 index 7d66d051..00000000 --- a/app/controllers/v0/uploads_controller.rb +++ /dev/null @@ -1,66 +0,0 @@ -module V0 -class UploadsController < ApplicationController - - before_action :check_if_authorized!, only: [:create] - after_action :verify_authorized, only: [:create] - - # create the document in rails, then send json back to our javascript to populate the form that will be - # going to amazon. - def create - check_missing_params 'filename' - @avatar = current_user.uploads.create(original_filename: params[:filename]) - authorize current_user, :update? - response.headers.except! 'X-Frame-Options' - render :json => { - :policy => s3_upload_policy_document, - :signature => s3_upload_signature, - :key => @avatar.key - # :success_action_redirect => devices_url - } - end - - def uploaded - check_missing_params 'key' - upload = Upload.find_by(key: CGI.unescape(params[:key]) ) - upload.user.update_attribute(:avatar_url, upload.full_path) - # head :ok - render json: {message: 'OK'}, status: :ok - end - - # # just in case you need to do anything after the document gets uploaded to amazon. - # # but since we are sending our docs via a hidden iframe, we don't need to show the user a - # # thank-you page. - # def s3_confirm - # head :ok - # end - -private - - # generate the policy document that amazon is expecting. - def s3_upload_policy_document - return @policy if @policy - ret = {"expiration" => 5.minutes.from_now.utc.xmlschema, - "conditions" => [ - {"bucket" => ENV['s3_bucket']}, - ["starts-with", "$key", @avatar.key], - {"acl" => "public-read"}, - {"success_action_status" => "200"}, - ["content-length-range", 0, 1073741824] # 100 MB - ] - } - @policy = Base64.encode64(ret.to_json).gsub(/\n/,'') - end - - # sign our request by Base64 encoding the policy document. - def s3_upload_signature - signature = Base64.encode64( - OpenSSL::HMAC.digest( - OpenSSL::Digest::Digest.new('sha1'), - (ENV['aws_secret_key'] || 'key_not_found'), - s3_upload_policy_document - ) - ).gsub("\n","") - end - - end -end diff --git a/app/controllers/v0/users_controller.rb b/app/controllers/v0/users_controller.rb index 1ec0f11c..056b1968 100644 --- a/app/controllers/v0/users_controller.rb +++ b/app/controllers/v0/users_controller.rb @@ -62,8 +62,6 @@ def user_params :city, :country_code, :url, - :avatar, - :avatar_url ) end diff --git a/app/helpers/presentation_helper.rb b/app/helpers/presentation_helper.rb new file mode 100644 index 00000000..3a0c8bac --- /dev/null +++ b/app/helpers/presentation_helper.rb @@ -0,0 +1,5 @@ +module PresentationHelper + def present(model, options={}) + Presenters.present(model, current_user, self, options) + end +end diff --git a/app/jobs/mqtt_forwarding_job.rb b/app/jobs/mqtt_forwarding_job.rb index 8707bc34..efe4aa0a 100644 --- a/app/jobs/mqtt_forwarding_job.rb +++ b/app/jobs/mqtt_forwarding_job.rb @@ -16,14 +16,7 @@ def perform(device_id, reading) private def payload_for(device, reading) - renderer.render( - partial: "v0/devices/device", - locals: { - device: device.reload, - current_user: nil, - slim_owner: true - } - ) + Presenters.present(device, device.owner, renderer, readings: [reading]) end def mqtt_client diff --git a/app/lib/presenters.rb b/app/lib/presenters.rb new file mode 100644 index 00000000..7e1bb077 --- /dev/null +++ b/app/lib/presenters.rb @@ -0,0 +1,26 @@ +module Presenters + # This is work in progress we're releasing early so + # that it can be used in forwarding to send the current + # values as they're received. + # TODO: add presenter tests, finish refactor following + # spec in your spreadsheet, remove unneeded options, + # use in appropriate views, add unauthorized_fields logic + # delete unneeded code in models and views. + PRESENTERS = { + Device => Presenters::DevicePresenter, + User => Presenters::UserPresenter, + Component => Presenters::ComponentPresenter, + Sensor => Presenters::SensorPresenter, + Measurement => Presenters::MeasurementPresenter, + } + + def self.present(model_or_collection, user, render_context, options={}) + if model_or_collection.is_a?(Enumerable) + model_or_collection.map { |model| present(model, user, render_context, options) } + else + PRESENTERS[model_or_collection.class]&.new( + model_or_collection, user, render_context, options + ).as_json + end + end +end diff --git a/app/lib/presenters/base_presenter.rb b/app/lib/presenters/base_presenter.rb new file mode 100644 index 00000000..27674423 --- /dev/null +++ b/app/lib/presenters/base_presenter.rb @@ -0,0 +1,42 @@ +module Presenters + class BasePresenter + + def default_options + {} + end + + def exposed_fields + [] + end + + def initialize(model, current_user=nil, render_context=nil, options={}) + @model = model + @current_user = current_user + @render_context = render_context + @options = self.default_options.merge(options) + end + + def as_json(_opts=nil) + self.exposed_fields.inject({}) { |hash, field| + value = self.send(field) + value.nil? ? hash : hash.merge(field => value) + } + end + + def method_missing(method, *args, &block) + if self.exposed_fields.include?(method) + model.public_send(method, *args, &block) + else + super + end + end + + def present(other_model, options={}) + Presenters.present(other_model, current_user, render_context, options) + end + + private + + attr_reader :model, :current_user, :options, :render_context + end +end diff --git a/app/lib/presenters/component_presenter.rb b/app/lib/presenters/component_presenter.rb new file mode 100644 index 00000000..00a81a12 --- /dev/null +++ b/app/lib/presenters/component_presenter.rb @@ -0,0 +1,46 @@ +module Presenters + class ComponentPresenter < BasePresenter + + alias_method :component, :model + + def default_options + { readings: nil } + end + + def exposed_fields + %i{key sensor last_reading_at latest_value previous_value readings} + end + + def sensor + present(component.sensor) + end + + def latest_value + data = component.device.data + data[component.sensor_id.to_s] if data + end + + def previous_value + old_data = component.device.old_data + old_data[component.sensor_id.to_s] if old_data + end + + def readings + readings = options[:readings] + if readings + readings.map { |reading| format_reading(reading) }.compact + end + end + + private + + def format_reading(reading) + timestamp = reading[""] + value = reading[component.sensor_id.to_s] + raw_value = reading["#{component.sensor_id}_raw"] + if value || raw_value + { timestamp: timestamp, value: value, raw_value: raw_value }.compact + end + end + end +end diff --git a/app/lib/presenters/device_presenter.rb b/app/lib/presenters/device_presenter.rb new file mode 100644 index 00000000..f6a4456a --- /dev/null +++ b/app/lib/presenters/device_presenter.rb @@ -0,0 +1,94 @@ +module Presenters + class DevicePresenter < BasePresenter + alias_method :device, :model + + def default_options + { + with_owner: true, + with_data: true, + with_postprocessing: true, + with_location: true, + slim_owner: false, + never_authorized: false, + readings: nil + } + end + + def exposed_fields + %i{id uuid name description state system_tags user_tags last_reading_at created_at updated_at notify device_token mac_address postprocessing location data_policy hardware owner components} + end + + def notify + { + stopped_publishing: device.notify_stopped_publishing, + low_battery: device.notify_low_battery + } + end + + def location + if options[:with_location] + { + exposure: device.exposure, + elevation: device.elevation.try(:to_i) , + latitude: device.latitude, + longitude: device.longitude, + geohash: device.geohash, + city: device.city, + country_code: device.country_code, + country: device.country_name + } + end + end + + def data_policy + { + is_private: authorized? ? device.is_private : "[FILTERED]", + enable_forwarding: authorized? ? device.enable_forwarding : "[FILTERED]", + precise_location: authorized? ? device.precise_location : "[FILTERED]" + } + end + + def hardware + { + name: device.hardware_name, + type: device.hardware_type, + version: device.hardware_version, + slug: device.hardware_slug, + last_status_message: authorized? ? device.hardware_info : "[FILTERED]", + } + end + + def owner + if options[:with_owner] && device.owner + present(device.owner, with_devices: false) + end + end + + def postprocessing + device.postprocessing if options[:with_postprocessing] + end + + def device_token + authorized? ? device.device_token : "[FILTERED]" + end + + def mac_address + authorized? ? device.mac_address : "[FILTERED]" + end + + def components + present(device.components) + end + + private + + def authorized? + !options[:never_authorized] && policy.show_private_info? + end + + def policy + @policy ||= DevicePolicy.new(current_user, device) + end + + end +end diff --git a/app/lib/presenters/measurement_presenter.rb b/app/lib/presenters/measurement_presenter.rb new file mode 100644 index 00000000..0c3cb98f --- /dev/null +++ b/app/lib/presenters/measurement_presenter.rb @@ -0,0 +1,10 @@ +module Presenters + class MeasurementPresenter < BasePresenter + + alias_method :measurement, :model + + def exposed_fields + %i{id name description unit uuid definition} + end + end +end diff --git a/app/lib/presenters/sensor_presenter.rb b/app/lib/presenters/sensor_presenter.rb new file mode 100644 index 00000000..da50c42a --- /dev/null +++ b/app/lib/presenters/sensor_presenter.rb @@ -0,0 +1,14 @@ +module Presenters + class SensorPresenter < BasePresenter + + alias_method :sensor, :model + + def exposed_fields + %i{id parent_id name description unit created_at updated_at uuid default_key datasheet unit_definition measurement tags} + end + + def measurement + present(sensor.measurement) + end + end +end diff --git a/app/lib/presenters/user_presenter.rb b/app/lib/presenters/user_presenter.rb new file mode 100644 index 00000000..e8991bb8 --- /dev/null +++ b/app/lib/presenters/user_presenter.rb @@ -0,0 +1,42 @@ +module Presenters + class UserPresenter < BasePresenter + + alias_method :user, :model + + def default_options + { + with_devices: true + } + end + + def exposed_fields + %i{id uuid role username profile_picture url location email legacy_api_key devices created_at updated_at} + end + + def profile_picture + render_context&.profile_picture_url(user) + end + + def email + user.email if authorized? + end + + def legacy_api_key + user.legacy_api_key if authorized? + end + + def devices + present(user.devices) if options[:with_devices] + end + + private + + def authorized? + policy.show_private_info? + end + + def policy + @policy ||= UserPolicy.new(current_user, user) + end + end +end diff --git a/app/models/avatar.rb b/app/models/avatar.rb deleted file mode 100644 index 5ef98838..00000000 --- a/app/models/avatar.rb +++ /dev/null @@ -1,5 +0,0 @@ -# This is the user's profile picture, it's stored in AWS S3 and is automatically -# resized using AWS Lambda. - -class Avatar < Upload -end diff --git a/app/models/device.rb b/app/models/device.rb index bcfdb98b..93d8ac66 100644 --- a/app/models/device.rb +++ b/app/models/device.rb @@ -194,6 +194,7 @@ def soft_state end end + # TODO Remove: Deprevated in API v1 def formatted_location { ip: nil, @@ -208,6 +209,7 @@ def formatted_location } end + # TODO Remove: Deprevated in API v1 def formatted_data s = { sensors: [] @@ -247,6 +249,7 @@ def update_component_timestamps(timestamp, sensor_ids) end end + # TODO Remove: Deprevated in API v1 def data_policy(authorized=false) { is_private: authorized ? is_private : "[FILTERED]", @@ -255,6 +258,7 @@ def data_policy(authorized=false) } end + # TODO Remove: Deprevated in API v1 def hardware(authorized=false) { name: hardware_name, diff --git a/app/models/raw_storer.rb b/app/models/raw_storer.rb index 0e46402b..905eea9c 100644 --- a/app/models/raw_storer.rb +++ b/app/models/raw_storer.rb @@ -62,18 +62,11 @@ def store data, mac, version, ip, raise_errors=false device.update_columns(last_reading_at: parsed_ts, data: sql_data, state: 'has_published') end - forward_reading(device, data) + forward_reading(device, sql_data) rescue Exception => e success = false raise e if raise_errors end - - if !Rails.env.test? and device - begin - Redis.current.publish("data-received", renderer.render( partial: "v0/devices/device", locals: {device: @device, current_user: nil})) - rescue - end - end end end diff --git a/app/models/storer.rb b/app/models/storer.rb index bd40d9cd..a93e14da 100644 --- a/app/models/storer.rb +++ b/app/models/storer.rb @@ -11,7 +11,7 @@ def store device, reading, do_update = true update_device(device, parsed_reading[:parsed_ts], parsed_reading[:sql_data]) end - forward_reading(device, reading) + forward_reading(device, parsed_reading[:sql_data]) rescue Exception => e Sentry.capture_exception(e) diff --git a/app/models/upload.rb b/app/models/upload.rb deleted file mode 100644 index 15083b02..00000000 --- a/app/models/upload.rb +++ /dev/null @@ -1,31 +0,0 @@ -# Only Avatars are uploaded right now, this is the base class that they inherit. -# Some of its methods are specific to Avatar, this needs to be fixed. - -require 'digest' - -class Upload < ActiveRecord::Base - - belongs_to :user - - before_create :generate_key - - def new_filename - [created_at.to_i.to_s(32), original_filename].join('.') - end - - def full_path - "https://images.smartcitizen.me/s100/#{key}" - end - - def self.uploaded _key - upload = Upload.find_by(key: _key) - upload.user.update_attribute(:avatar_url, upload.key) - end - -private - - def generate_key - self.key = ['avatars', user.uuid[0..2], new_filename].join('/') - end - -end diff --git a/app/models/user.rb b/app/models/user.rb index 49cb1992..ebeb2f00 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -33,7 +33,6 @@ class User < ActiveRecord::Base has_many :devices, foreign_key: 'owner_id', after_add: :update_cached_device_ids!, after_remove: :update_cached_device_ids! has_many :sensors, through: :devices - has_many :uploads, dependent: :destroy has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner has_one_attached :profile_picture @@ -50,7 +49,7 @@ def self.ransackable_attributes(auth_object = nil) end def self.ransackable_associations(auth_object = nil) - ["devices", "sensors", "uploads"] + ["devices", "sensors"] end def archive @@ -69,10 +68,6 @@ def access_token Doorkeeper::AccessToken.find_or_initialize_by(application_id: 4, resource_owner_id: id) end - def avatar - avatar_url || "https://smartcitizen.s3.amazonaws.com/avatars/default.svg" - end - def access_token! access_token.expires_in = 2.days.from_now access_token.save @@ -142,14 +137,6 @@ def update_all_device_ids! update_column(:cached_device_ids, device_ids.try(:sort)) end - def self.check_bad_avatar_urls - User.where.not(avatar_url: nil).each do |user| - unless `curl -I #{user.avatar_url} 2>/dev/null | head -n 1`.split(' ')[1] == "200" - puts [user.id, user.avatar_url].join(' - ') - end - end - end - def forward_device_readings? !!forwarding_token end diff --git a/app/policies/device_policy.rb b/app/policies/device_policy.rb index 291f2d7d..5da4b678 100644 --- a/app/policies/device_policy.rb +++ b/app/policies/device_policy.rb @@ -23,15 +23,23 @@ def resolve end end + def show_private_info? + admin_or_owner? + end + def show? if record.is_private? - update? + admin_or_owner? else true end end def update? + admin_or_owner? + end + + def admin_or_owner? user.try(:is_admin?) || user == record.owner end diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index 92b64eb9..716cb4a7 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -24,4 +24,7 @@ def update_password? update? end + def show_private_info? + update? + end end diff --git a/app/views/v0/devices/_device.jbuilder b/app/views/v0/devices/_device.jbuilder index 59e5edee..14ebb6ae 100644 --- a/app/views/v0/devices/_device.jbuilder +++ b/app/views/v0/devices/_device.jbuilder @@ -45,7 +45,6 @@ if local_assigns[:with_owner] && device.owner json.url device.owner.url unless local_assigns[:slim_owner] - json.avatar device.owner.avatar json.profile_picture profile_picture_url(device.owner) json.location device.owner.location json.device_ids device.owner.cached_device_ids diff --git a/app/views/v0/users/_user.jbuilder b/app/views/v0/users/_user.jbuilder index 7543208e..934dc4e2 100644 --- a/app/views/v0/users/_user.jbuilder +++ b/app/views/v0/users/_user.jbuilder @@ -3,7 +3,6 @@ json.(user, :uuid, :role, :username, - :avatar, :profile_picture, :url, :location, diff --git a/config/routes.rb b/config/routes.rb index e0a8cec5..04bf9c98 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -26,10 +26,6 @@ resources :components, only: [:show, :index] resources :sessions, only: :create - resources :uploads, path: 'avatars' do - post 'uploaded' => 'uploads#uploaded', on: :collection - end - resources :tag_sensors resources :tags resources :measurements @@ -39,8 +35,6 @@ get :forward, to: "forwarding#authorize" resources :me, only: [:index] do - patch 'avatar' => 'uploads#create', on: :collection - post 'avatar' => 'uploads#create', on: :collection patch '/' => 'me#update', on: :collection put '/' => 'me#update', on: :collection delete '/' => 'me#destroy', on: :collection diff --git a/db/migrate/20240704062854_remove_avatars_and_uploads.rb b/db/migrate/20240704062854_remove_avatars_and_uploads.rb new file mode 100644 index 00000000..2f47f75f --- /dev/null +++ b/db/migrate/20240704062854_remove_avatars_and_uploads.rb @@ -0,0 +1,4 @@ +class RemoveAvatarsAndUploads < ActiveRecord::Migration[6.1] + def change + end +end diff --git a/db/schema.rb b/db/schema.rb index 4f1bb703..c4df0627 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2024_06_24_175242) do +ActiveRecord::Schema.define(version: 2024_07_04_062854) do # These are extensions that must be enabled in order to support this database enable_extension "adminpack" diff --git a/public/examples/image_uploads/form.html b/public/examples/image_uploads/form.html deleted file mode 100644 index 263a6b8d..00000000 --- a/public/examples/image_uploads/form.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - -Example Uploader - - - - -
- - - - - - - -
-
-
-
- -
-
-
- - - - - - - - - - \ No newline at end of file diff --git a/spec/controllers/v0/me_controller_spec.rb b/spec/controllers/v0/me_controller_spec.rb index 0ddfeaa9..b63ce9bc 100644 --- a/spec/controllers/v0/me_controller_spec.rb +++ b/spec/controllers/v0/me_controller_spec.rb @@ -1,5 +1,5 @@ require 'rails_helper' RSpec.describe V0::MeController do - skip { is_expected.to permit(:email,:username,:password,:city,:country_code,:url,:avatar,:avatar_url).for(:update) } + skip { is_expected.to permit(:email,:username,:password,:city,:country_code,:url).for(:update) } end diff --git a/spec/controllers/v0/users_controller_spec.rb b/spec/controllers/v0/users_controller_spec.rb index 324af31f..641ded0d 100644 --- a/spec/controllers/v0/users_controller_spec.rb +++ b/spec/controllers/v0/users_controller_spec.rb @@ -1,5 +1,5 @@ require 'rails_helper' RSpec.describe V0::UsersController do - it { is_expected.to permit(:email,:username,:password,:city,:country_code,:url,:avatar,:avatar_url).for(:create) } + it { is_expected.to permit(:email,:username,:password,:city,:country_code,:url).for(:create) } end diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb deleted file mode 100644 index 67a4556f..00000000 --- a/spec/factories/uploads.rb +++ /dev/null @@ -1,9 +0,0 @@ -FactoryBot.define do - - factory :upload do - type { "Avatar" } - association :user - original_filename { "testing.jpg" } - end - -end diff --git a/spec/jobs/mqtt_forwarding_job_spec.rb b/spec/jobs/mqtt_forwarding_job_spec.rb index 24b273d1..1ae052d7 100644 --- a/spec/jobs/mqtt_forwarding_job_spec.rb +++ b/spec/jobs/mqtt_forwarding_job_spec.rb @@ -19,9 +19,7 @@ } let(:renderer) { - double(:renderer).tap do |renderer| - allow(renderer).to receive(:render).and_return(device_json) - end + double(:renderer) } let(:forwarder) { @@ -32,6 +30,7 @@ before do allow(MQTTClientFactory).to receive(:create_client).and_return(mqtt_client) + allow(Presenters).to receive(:present).and_return(device_json) allow_any_instance_of(ActionController::Base).to receive(:view_context).and_return(renderer) allow(MQTTForwarder).to receive(:new).and_return(forwarder) allow_any_instance_of(Device).to receive(:forwarding_token).and_return(forwarding_token) @@ -50,16 +49,9 @@ expect(MQTTForwarder).to have_received(:new).with(mqtt_client) end - it "renders the device json for the given device, as an unauthorized user" do + it "renders the device json for the given device and reading, as the device owner" do MQTTForwardingJob.perform_now(device.id, reading) - expect(renderer).to have_received(:render).with({ - partial: "v0/devices/device", - locals: { - device: device.reload, - current_user: nil, - slim_owner: true - } - }) + expect(Presenters).to have_received(:present).with(device, device.owner, renderer, readings: [reading]) end it "forwards using the device's id and forwarding token, with the rendered json payload" do diff --git a/spec/models/raw_storer_spec.rb b/spec/models/raw_storer_spec.rb index 989e1ab2..69772fb7 100644 --- a/spec/models/raw_storer_spec.rb +++ b/spec/models/raw_storer_spec.rb @@ -92,7 +92,8 @@ def to_ts(time) context "when the device allows forwarding" do it "forwards the message" do allow_any_instance_of(Device).to receive(:forward_readings?).and_return(true) - expect(MQTTForwardingJob).to receive(:perform_later).with(device.id, json) + # TODO assert that the correct arguments are called after refactoring device representations + expect(MQTTForwardingJob).to receive(:perform_later) storer.store(json, device.mac_address, "1.1-0.9.0-A", "127.0.0.1", true) end end diff --git a/spec/models/storer_spec.rb b/spec/models/storer_spec.rb index 43923a15..00d648da 100644 --- a/spec/models/storer_spec.rb +++ b/spec/models/storer_spec.rb @@ -20,6 +20,13 @@ 'sensors'=> [{ 'id'=> sensor.id, 'value'=>21 }] } + # TODO get rid of this fucked-up intermediate representation + @sql_data = { + "" => Time.parse(@data["recorded_at"]), + "#{sensor.id}_raw" => 21, + sensor.id => component.calibrated_value(21) + } + sensor_key = device.find_sensor_key_by_id(sensor.id) normalized_value = component.normalized_value((Float(@data['sensors'][0]['value']))) calibrated_value = component.calibrated_value(normalized_value) @@ -77,7 +84,7 @@ it "forwards the message with the forwarding token and the device's id" do allow(device).to receive(:forward_readings?).and_return(true) - expect(MQTTForwardingJob).to receive(:perform_later).with(device.id, @data) + expect(MQTTForwardingJob).to receive(:perform_later).with(device.id, @sql_data) storer.store(device, @data) end end diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb deleted file mode 100644 index 8581d395..00000000 --- a/spec/models/upload_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'rails_helper' - -RSpec.describe Upload, type: :model do - - it { is_expected.to belong_to(:user) } - - let(:user) { create(:user) } - let(:upload) { create(:upload, user: user, original_filename: 'testing.jpg') } - - it "works with filenames with spaces" - - it "works with filenames with special characters" - - it "has a new_filename" do - expect(upload.new_filename).to eq("#{upload.created_at.to_i.to_s(32)}.testing.jpg") - end - - it "has self.uploaded method" do - expect(user.avatar_url).to be_nil - Upload.uploaded( upload.key ) - user.reload - expect(user.avatar_url).to eq(upload.key) - end - - it "generates key on create and has full_path" do - Timecop.freeze do - expect(upload.key).to eq("avatars/#{upload.user.uuid[0..2]}/#{upload.created_at.to_i.to_s(32)}.testing.jpg") - expect(upload.full_path).to eq("https://images.smartcitizen.me/s100/#{upload.key}") - end - end - -end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a764acbf..f2a6b69c 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -18,8 +18,6 @@ let(:user) { create(:user) } let(:homer) { build_stubbed(:user, username: 'homersimpson', email: 'homer@springfieldnuclear.com') } - it "has an avatar" - it "validates url" do expect(build(:user, url: nil)).to be_valid expect(build(:user, url: 'not a url')).to be_invalid @@ -27,13 +25,6 @@ expect(build(:user, url: 'https://www.facebook.com')).to be_valid end - skip "validates avatar" do - expect(build(:user, avatar: nil)).to be_valid - expect(build(:user, avatar: 'not a url')).to be_invalid - expect(build(:user, avatar: 'https://i.imgur.com/SZD8ADL.png')).to be_valid - expect(build(:user, avatar: 'http://i.imgur.com/SZD8ADL.JPEG')).to be_valid - end - it "is invalid with an email which isn't an email adddress" do expect(build(:user, email: "not an email")).to be_invalid end diff --git a/spec/requests/v0/uploads_spec.rb b/spec/requests/v0/uploads_spec.rb deleted file mode 100644 index 49f0b1fd..00000000 --- a/spec/requests/v0/uploads_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'rails_helper' - -describe V0::UploadsController do - - let(:application) { create :application } - let(:user) { create :user } - let(:token) { create :access_token, application: application, resource_owner_id: user.id } - - describe "/POST" do - - it "creates an upload" do - j = api_post "avatars", - access_token: token.token, - filename: "test.jpg" - expect(response.status).to eq(200) - user.reload - expect(j['policy']).to_not be_blank - expect(j['signature']).to_not be_blank - expect(j['key']).to eq(user.uploads.last.key) - end - - it "requires filename" do - j = api_post "avatars", - access_token: token.token - expect(response.status).to eq(400) - end - - it "requires access_token" do - j = api_post "avatars", - filename: "test.jpg" - expect(response.status).to eq(401) - end - - end - - describe "amazon s3 callback" do - - let(:upload) { create(:upload, user: user) } - - it "responds to uploaded" do - # i know this doesn't belong here, but needed to check - expect(user.avatar_url).to be_blank - j = api_post "avatars/uploaded", key: upload.key - user.reload - expect(user.avatar_url).to eq(upload.full_path) - expect(response.status).to eq(200) - end - - it "requires key" do - j = api_post "avatars/uploaded" - expect(j['id']).to eq('parameter_missing') - expect(response.status).to eq(400) - end - - end - -end