Store client's user agent on Asciicast record

openid
Marcin Kulik 11 years ago
parent e4cb9c0657
commit d74ead2263

@ -3,7 +3,7 @@ class Api::AsciicastsController < ApplicationController
skip_before_filter :verify_authenticity_token
def create
asciicast = AsciicastCreator.new.create(params[:asciicast])
asciicast = AsciicastCreator.new.create(params[:asciicast], request.headers)
render :text => asciicast_url(asciicast), :status => :created,
:location => asciicast
rescue ActiveRecord::RecordInvalid => e

@ -5,14 +5,12 @@ class AsciicastDecorator < ApplicationDecorator
THUMBNAIL_HEIGHT = 10
def os
return 'unknown' if uname.blank?
if uname =~ /Linux/
'Linux'
elsif uname =~ /Darwin/
'OSX'
if user_agent.present?
os_from_user_agent
elsif uname.present?
os_from_uname
else
uname.split(' ', 2)[0]
'unknown'
end
end
@ -99,4 +97,27 @@ class AsciicastDecorator < ApplicationDecorator
"%02d:%02d" % [minutes, seconds]
end
private
def os_from_user_agent
match = user_agent.match(/^[^\s]+\s+\(([^\)]+)\)/)
os = match[1].split(/(\s|-)/).first
guess_os(os)
end
def os_from_uname
guess_os(uname)
end
def guess_os(text)
if text =~ /Linux/
'Linux'
elsif text =~ /Darwin/
'OSX'
else
text.split(' ', 2)[0]
end
end
end

@ -1,21 +1,23 @@
class AsciicastParams
def initialize(input)
@input = input
def initialize(params, headers)
@params = params
@headers = headers
end
def to_h
attributes = {
:stdout_data => input[:stdout],
:stdout_timing => input[:stdout_timing],
:stdin_data => input[:stdin],
:stdin_timing => input[:stdin_timing],
:stdout_data => params[:stdout],
:stdout_timing => params[:stdout_timing],
:stdin_data => params[:stdin],
:stdin_timing => params[:stdin_timing],
:username => meta['username'],
:duration => meta['duration'],
:recorded_at => meta['recorded_at'],
:title => meta['title'],
:command => meta['command'],
:shell => meta['shell'],
:user_agent => headers['User-Agent'],
:uname => meta['uname'],
:terminal_lines => meta['term']['lines'],
:terminal_columns => meta['term']['columns'],
@ -29,10 +31,10 @@ class AsciicastParams
private
attr_reader :input
attr_reader :params, :headers
def meta
@meta ||= JSON.parse(input[:meta].read)
@meta ||= JSON.parse(params[:meta].read)
end
def assign_user_or_token(attributes, meta)

@ -1,7 +1,7 @@
class AsciicastCreator
def create(attributes)
attributes = AsciicastParams.new(attributes).to_h
def create(attributes, headers)
attributes = AsciicastParams.new(attributes, headers).to_h
asciicast = Asciicast.create!(attributes, without_protection: true)
AsciicastWorker.perform_async(asciicast.id)

@ -0,0 +1,5 @@
class AddUserAgentToAsciicast < ActiveRecord::Migration
def change
add_column :asciicasts, :user_agent, :string
end
end

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20130828162232) do
ActiveRecord::Schema.define(version: 20131011181418) do
create_table "asciicasts", force: true do |t|
t.integer "user_id"
@ -40,6 +40,7 @@ ActiveRecord::Schema.define(version: 20130828162232) do
t.boolean "time_compression", default: true, null: false
t.integer "views_count", default: 0, null: false
t.string "stdout_frames"
t.string "user_agent"
end
add_index "asciicasts", ["created_at"], name: "index_asciicasts_on_created_at", using: :btree

@ -14,7 +14,8 @@ describe Api::AsciicastsController do
let(:asciicast) { stub_model(Asciicast, :id => 666) }
before do
allow(creator).to receive(:create).with(attributes) { asciicast }
allow(creator).to receive(:create).
with(attributes, kind_of(ActionDispatch::Http::Headers)) { asciicast }
post :create, :asciicast => attributes
end
@ -33,7 +34,8 @@ describe Api::AsciicastsController do
let(:full_messages) { ['This is invalid'] }
before do
allow(creator).to receive(:create).with(attributes).
allow(creator).to receive(:create).
with(attributes, kind_of(ActionDispatch::Http::Headers)).
and_raise(ActiveRecord::RecordInvalid.new(asciicast))
post :create, :asciicast => attributes
end
@ -42,7 +44,7 @@ describe Api::AsciicastsController do
expect(response.status).to eq(422)
end
it 'returns the full error messages as the content body' do
it 'returns nothing as the content body' do
expect(response.body).to be_blank
end
end

@ -11,42 +11,76 @@ describe AsciicastDecorator do
describe '#os' do
let(:method) { :os }
context 'for Linux-like uname' do
before do
asciicast.uname = "Linux t430u 3.5.0-18-generic #29-Ubuntu SMP"
context 'when user_agent is present' do
context 'and the OS is Linux' do
before do
asciicast.user_agent =
"asciinema/0.9.7 " \
"(Linux-3.8.0-30-generic-x86_64-with-Ubuntu-13.04-raring)"
end
it { should == 'Linux' }
end
it { should == 'Linux' }
end
context 'and the OS is OSX' do
before do
asciicast.user_agent = "asciinema/0.9.7 (Darwin-10.0.0-i386-64bit)"
end
context 'for Darwin-like uname' do
before do
asciicast.uname = "Darwin local 10.3.0 Darwin Kernel Version 10.3.0"
it { should == 'OSX' }
end
it { should == 'OSX' }
context 'and the OS is other' do
before do
asciicast.user_agent = "asciinema/0.9.7 (Jola Misio Foo)"
end
it 'should return first token' do
should == 'Jola'
end
end
end
context 'for other systems' do
before do
asciicast.uname = "Jola Misio Foo"
context 'when uname is present' do
context "and it's Linux-like" do
before do
asciicast.uname = "Linux t430u 3.5.0-18-generic #29-Ubuntu SMP"
end
it { should == 'Linux' }
end
it 'should return first token' do
should == 'Jola'
context "and it's Darwin-like" do
before do
asciicast.uname = "Darwin local 10.3.0 Darwin Kernel Version 10.3.0"
end
it { should == 'OSX' }
end
context "and it's other" do
before do
asciicast.uname = "Jola Misio Foo"
end
it 'should return first token' do
should == 'Jola'
end
end
end
context 'when uname is nil' do
context 'when user_agent and uname are nil' do
before do
asciicast.user_agent = nil
asciicast.uname = nil
end
it { should == 'unknown' }
end
context 'when uname is blank string' do
context 'when user_agent and uname are a blank string' do
before do
asciicast.user_agent = ' '
asciicast.uname = ' '
end

@ -2,13 +2,14 @@ require 'spec_helper'
describe AsciicastParams do
let(:asciicast_params) { described_class.new(input) }
let(:asciicast_params) { described_class.new(input, headers) }
let(:input) { {
:meta => meta_file,
:stdout => stdout_data_file,
:stdout_timing => stdout_timing_file
} }
let(:headers) { { 'User-Agent' => 'asciinema/0.9.7' } }
let(:stdout_data_file) { double('stdout_data_file') }
let(:stdout_timing_file) { double('stdout_timing_file') }
@ -25,6 +26,7 @@ describe AsciicastParams do
:title => 'bashing :)',
:command => '/bin/bash',
:shell => '/bin/zsh',
:user_agent => 'asciinema/0.9.7',
:uname => 'Linux 3.9.9-302.fc19.x86_64 #1 SMP ' +
'Sat Jul 6 13:41:07 UTC 2013 x86_64',
:terminal_columns => 96,

@ -7,13 +7,14 @@ describe AsciicastCreator do
describe '#create' do
let(:asciicast) { stub_model(Asciicast, id: 666) }
let(:input_attrs) { { a: 'A' } }
let(:headers) { { 'User-Agent' => 'asciinema/0.9.7' } }
let(:prepared_attrs) { { b: 'B' } }
subject { creator.create(input_attrs) }
subject { creator.create(input_attrs, headers) }
before do
allow(AsciicastParams).to receive(:new).
with(input_attrs) { prepared_attrs }
with(input_attrs, headers) { prepared_attrs }
allow(Asciicast).to receive(:create!) { asciicast }
end

Loading…
Cancel
Save