diff --git a/app/models/concerns/akismet_submittable.rb b/app/models/concerns/akismet_submittable.rb new file mode 100644 index 0000000000000000000000000000000000000000..178216889411c902d0847d37f0eeeeef2249b724 --- /dev/null +++ b/app/models/concerns/akismet_submittable.rb @@ -0,0 +1,15 @@ +module AkismetSubmittable + extend ActiveSupport::Concern + + included do + has_one :user_agent_detail, as: :subject + end + + def can_be_submitted? + if user_agent_detail + user_agent_detail.submittable? + else + false + end + end +end diff --git a/app/models/issue.rb b/app/models/issue.rb index d62ffb214678f99723daf780f08a75b1851b295f..6c2635498e5f23d6ce38c08eacfe609567e46074 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -8,6 +8,7 @@ class Issue < ActiveRecord::Base include Taskable include Spammable include FasterCacheKeys + include AkismetSubmittable DueDateStruct = Struct.new(:title, :name).freeze NoDueDate = DueDateStruct.new('No Due Date', '0').freeze diff --git a/app/models/user_agent_detail.rb b/app/models/user_agent_detail.rb new file mode 100644 index 0000000000000000000000000000000000000000..6d76dff20e3ee6232c74031f0622187ea61c2d9e --- /dev/null +++ b/app/models/user_agent_detail.rb @@ -0,0 +1,16 @@ +class UserAgentDetail < ActiveRecord::Base + belongs_to :subject, polymorphic: true + + validates :user_agent, + presence: true + validates :ip_address, + presence: true + validates :subject_id, + presence: true + validates :subject_type, + presence: true + + def submittable? + user_agent.present? && ip_address.present? + end +end diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb index 5e2de2ccf64528942cddf0482320ac5f5d7a2483..8e9d74103c782410666aa0200fc057ac5d52c8d0 100644 --- a/app/services/issues/create_service.rb +++ b/app/services/issues/create_service.rb @@ -15,6 +15,7 @@ module Issues notification_service.new_issue(issue, current_user) todo_service.new_issue(issue, current_user) event_service.open_issue(issue, current_user) + user_agent_detail_service(issue, request).create issue.create_cross_references!(current_user) execute_hooks(issue, 'open') end @@ -27,5 +28,9 @@ module Issues def spam_check_service SpamCheckService.new(project, current_user, params) end + + def user_agent_detail_service(issue, request) + UserAgentDetailService.new(issue, request) + end end end diff --git a/app/services/user_agent_detail_service.rb b/app/services/user_agent_detail_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..dd995955be320458c167593b71e9acc88eace2f6 --- /dev/null +++ b/app/services/user_agent_detail_service.rb @@ -0,0 +1,12 @@ +class UserAgentDetailService + attr_accessor :subject, :request + + def initialize(subject, request) + @subject, @request = subject, request + end + + def create + return unless request + subject.create_user_agent_detail(user_agent: request.env['HTTP_USER_AGENT'], ip_address: request.env['action_dispatch.remote_ip'].to_s) + end +end diff --git a/db/migrate/20160727163552_create_user_agent_details.rb b/db/migrate/20160727163552_create_user_agent_details.rb new file mode 100644 index 0000000000000000000000000000000000000000..05c21a476fa85d7584d9dd27dc1d035595320e4c --- /dev/null +++ b/db/migrate/20160727163552_create_user_agent_details.rb @@ -0,0 +1,12 @@ +class CreateUserAgentDetails < ActiveRecord::Migration + def change + create_table :user_agent_details do |t| + t.string :user_agent, null: false + t.string :ip_address, null: false + t.integer :subject_id, null: false + t.string :subject_type, null: false + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index f008a6bd7a7dcb3ef181710ce1357ad8d8b1d32e..2e5ffac5935a048de1f3a195a777bd8071cb2b10 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -999,6 +999,15 @@ ActiveRecord::Schema.define(version: 20160810142633) do add_index "u2f_registrations", ["key_handle"], name: "index_u2f_registrations_on_key_handle", using: :btree add_index "u2f_registrations", ["user_id"], name: "index_u2f_registrations_on_user_id", using: :btree + create_table "user_agent_details", force: :cascade do |t| + t.string "user_agent", null: false + t.string "ip_address", null: false + t.integer "subject_id", null: false + t.string "subject_type", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index b6a0276846cacbc8e7f8f046b91a3b4fdeccaa56..4e39826d6944a15cb89ca67b9cd42d39b49536d5 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -300,6 +300,26 @@ describe Projects::IssuesController do expect(spam_logs[0].title).to eq('Spam Title') end end + + context 'user agent details are saved' do + before do + request.env['action_dispatch.remote_ip'] = '127.0.0.1' + end + + def post_new_issue + sign_in(user) + project = create(:empty_project, :public) + post :create, { + namespace_id: project.namespace.to_param, + project_id: project.to_param, + issue: { title: 'Title', description: 'Description' } + } + end + + it 'creates a user agent detail' do + expect{ post_new_issue }.to change(UserAgentDetail, :count) + end + end end describe "DELETE #destroy" do diff --git a/spec/factories/user_agent_details.rb b/spec/factories/user_agent_details.rb new file mode 100644 index 0000000000000000000000000000000000000000..5fc40915911e2f9ca422bc41a78d4159eadc7ae7 --- /dev/null +++ b/spec/factories/user_agent_details.rb @@ -0,0 +1,10 @@ +FactoryGirl.define do + factory :user_agent_detail do + ip_address '127.0.0.1' + user_agent 'AppleWebKit/537.36' + + trait :on_issue do + association :subject, factory: :issue + end + end +end diff --git a/spec/models/user_agent_detail_spec.rb b/spec/models/user_agent_detail_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..8debcbbeba683dafd65a71b555774301b9b33339 --- /dev/null +++ b/spec/models/user_agent_detail_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +describe UserAgentDetail, type: :model do + describe '.submittable?' do + it 'should be submittable' do + detail = create(:user_agent_detail, :on_issue) + expect(detail.submittable?).to be_truthy + end + end + + describe '.valid?' do + it 'should be valid with a subject' do + detail = create(:user_agent_detail, :on_issue) + expect(detail).to be_valid + end + + it 'should not be valid without a subject' do + detail = build(:user_agent_detail) + expect(detail).not_to be_valid + end + end +end