Init version of device logging.
This commit is contained in:
parent
94c4906264
commit
7d17849214
8 changed files with 205 additions and 1 deletions
1
Gemfile
1
Gemfile
|
@ -55,6 +55,7 @@ gem 'net-ldap'
|
||||||
|
|
||||||
gem 'writeexcel'
|
gem 'writeexcel'
|
||||||
gem 'icalendar'
|
gem 'icalendar'
|
||||||
|
gem 'browser'
|
||||||
|
|
||||||
# event machine
|
# event machine
|
||||||
gem 'eventmachine'
|
gem 'eventmachine'
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
class Index extends App.Controller
|
||||||
|
events:
|
||||||
|
'click [data-type=delete]': 'delete'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
return if !@authenticate()
|
||||||
|
@title 'Devices', true
|
||||||
|
|
||||||
|
@load()
|
||||||
|
@interval(
|
||||||
|
=>
|
||||||
|
@load()
|
||||||
|
62000
|
||||||
|
)
|
||||||
|
|
||||||
|
# fetch data, render view
|
||||||
|
load: =>
|
||||||
|
@ajax(
|
||||||
|
id: 'user_devices'
|
||||||
|
type: 'GET'
|
||||||
|
url: @apiPath + '/user_devices'
|
||||||
|
success: (data) =>
|
||||||
|
@render(data)
|
||||||
|
)
|
||||||
|
|
||||||
|
render: (data) =>
|
||||||
|
@html App.view('profile/devices')( devices: data )
|
||||||
|
|
||||||
|
delete: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
id = $(e.target).closest('a').data('device-id')
|
||||||
|
console.log('ID', id)
|
||||||
|
# get data
|
||||||
|
@ajax(
|
||||||
|
id: 'user_devices_delete'
|
||||||
|
type: 'DELETE'
|
||||||
|
url: "#{@apiPath}/user_devices/#{id}"
|
||||||
|
processData: true
|
||||||
|
success: @load
|
||||||
|
error: @error
|
||||||
|
)
|
||||||
|
|
||||||
|
error: (xhr, status, error) =>
|
||||||
|
data = JSON.parse( xhr.responseText )
|
||||||
|
@notify(
|
||||||
|
type: 'error'
|
||||||
|
msg: App.i18n.translateContent( data.message )
|
||||||
|
)
|
||||||
|
|
||||||
|
App.Config.set( 'Devices', { prio: 3100, name: 'Devices', parent: '#profile', target: '#profile/devices', controller: Index }, 'NavBarProfile' )
|
30
app/assets/javascripts/app/views/profile/devices.jst.eco
Normal file
30
app/assets/javascripts/app/views/profile/devices.jst.eco
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="page-header-title"><h1><%- @T( 'Devices' ) %></h1></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
|
||||||
|
<p><%- @T('All computers and browsers that have access to your Zammad appear here.') %></p>
|
||||||
|
|
||||||
|
<table class="settings-list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%- @T('Name') %></th>
|
||||||
|
<th><%- @T('Location') %></th>
|
||||||
|
<th><%- @T('Most recent activity') %></th>
|
||||||
|
<th><%- @T('Remove') %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% for device in @devices: %>
|
||||||
|
<tr>
|
||||||
|
<td><%= device.name %></td>
|
||||||
|
<td><%= device.location %></td>
|
||||||
|
<td><%- @humanTime(device.updated_at) %></td>
|
||||||
|
<td><a href="#" data-device-id="<%- device.id %>" data-type="delete" title="<%- @Ti('Delete') %>"><svg class="icon-trash"><use xlink:href="#icon-trash"></use></svg></a></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
<tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</form>
|
|
@ -14,7 +14,7 @@ class ApplicationController < ActionController::Base
|
||||||
:model_index_render
|
:model_index_render
|
||||||
|
|
||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
before_action :set_user, :session_update
|
before_action :set_user, :session_update, :check_user_device
|
||||||
before_action :cors_preflight_check
|
before_action :cors_preflight_check
|
||||||
|
|
||||||
after_action :set_access_control_headers
|
after_action :set_access_control_headers
|
||||||
|
@ -95,6 +95,26 @@ class ApplicationController < ActionController::Base
|
||||||
session[:user_agent] = request.env['HTTP_USER_AGENT']
|
session[:user_agent] = request.env['HTTP_USER_AGENT']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# check user device
|
||||||
|
def check_user_device
|
||||||
|
|
||||||
|
# only if user_id exists
|
||||||
|
return if !session[:user_id]
|
||||||
|
|
||||||
|
# only if write action
|
||||||
|
return if request.method == 'GET' || request.method == 'OPTIONS'
|
||||||
|
|
||||||
|
# only update if needed
|
||||||
|
return if session[:check_user_device_at] && session[:check_user_device_at] < Time.zone.now - 10.minutes
|
||||||
|
session[:check_user_device_at] = Time.zone.now
|
||||||
|
|
||||||
|
UserDevice.add(
|
||||||
|
session[:user_agent],
|
||||||
|
session[:remote_id],
|
||||||
|
session[:user_id],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def authentication_check_only(auth_param)
|
def authentication_check_only(auth_param)
|
||||||
|
|
||||||
logger.debug 'authentication_check'
|
logger.debug 'authentication_check'
|
||||||
|
|
69
app/models/user_device.rb
Normal file
69
app/models/user_device.rb
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class UserDevice < ApplicationModel
|
||||||
|
store :device_details
|
||||||
|
store :location_details
|
||||||
|
validates :name, presence: true
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
store device for user
|
||||||
|
|
||||||
|
UserDevice.add(
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36',
|
||||||
|
'172.0.0.1',
|
||||||
|
user.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def self.add(user_agent, ip, user_id)
|
||||||
|
|
||||||
|
# get browser details
|
||||||
|
browser = Browser.new(:ua => user_agent, :accept_language => 'en-us')
|
||||||
|
browser = {
|
||||||
|
plattform: browser.platform.to_s.camelize,
|
||||||
|
name: browser.name,
|
||||||
|
version: browser.version,
|
||||||
|
full_version: browser.full_version,
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate device name
|
||||||
|
name = browser[:plattform] || ''
|
||||||
|
if browser[:name]
|
||||||
|
if name
|
||||||
|
name += ', '
|
||||||
|
end
|
||||||
|
name += browser[:name]
|
||||||
|
end
|
||||||
|
|
||||||
|
# get location info
|
||||||
|
location = Service::GeoIp.location(ip)
|
||||||
|
country = location['country_name']
|
||||||
|
|
||||||
|
# check if exists
|
||||||
|
exists = self.find_by(
|
||||||
|
:user_id => user_id,
|
||||||
|
os: browser[:plattform],
|
||||||
|
browser: browser[:name],
|
||||||
|
country: country,
|
||||||
|
)
|
||||||
|
|
||||||
|
if exists
|
||||||
|
exists.touch
|
||||||
|
return exists
|
||||||
|
end
|
||||||
|
|
||||||
|
# create new device
|
||||||
|
self.create(
|
||||||
|
user_id: user_id,
|
||||||
|
name: name,
|
||||||
|
os: browser[:plattform],
|
||||||
|
browser: browser[:name],
|
||||||
|
country: country,
|
||||||
|
device_details: browser,
|
||||||
|
location_details: location,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
8
config/routes/user_devices.rb
Normal file
8
config/routes/user_devices.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
|
# jobs
|
||||||
|
match api_path + '/user_devices', to: 'user_devices#index', via: :get
|
||||||
|
match api_path + '/user_devices/:id', to: 'user_devices#destroy', via: :delete
|
||||||
|
|
||||||
|
end
|
22
db/migrate/20150817000001_create_user_devices.rb
Normal file
22
db/migrate/20150817000001_create_user_devices.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
class CreateUserDevices < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
create_table :user_devices do |t|
|
||||||
|
t.references :user, null: false
|
||||||
|
t.string :name, limit: 250, null: false
|
||||||
|
t.string :os, limit: 150, null: true
|
||||||
|
t.string :browser, limit: 250, null: true
|
||||||
|
t.string :country, limit: 150, null: true
|
||||||
|
t.string :device_details, limit: 2500, null: true
|
||||||
|
t.string :location_details, limit: 2500, null: true
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
add_index :user_devices, [:user_id]
|
||||||
|
add_index :user_devices, [:os, :browser, :country]
|
||||||
|
add_index :user_devices, [:updated_at]
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
drop_table :user_devices
|
||||||
|
end
|
||||||
|
end
|
|
@ -35,6 +35,9 @@ returns
|
||||||
model_class = load_adapter(entry)
|
model_class = load_adapter(entry)
|
||||||
next if !model_class
|
next if !model_class
|
||||||
next if !model_class.respond_to? :new
|
next if !model_class.respond_to? :new
|
||||||
|
next if !model_class.respond_to? :table_name
|
||||||
|
table_name = model_class.table_name # handle models where not table exists, pending migrations
|
||||||
|
next if !ActiveRecord::Base.connection.tables.include?(table_name)
|
||||||
model_object = model_class.new
|
model_object = model_class.new
|
||||||
next if !model_object.respond_to? :attributes
|
next if !model_object.respond_to? :attributes
|
||||||
all[model_class] = {}
|
all[model_class] = {}
|
||||||
|
|
Loading…
Reference in a new issue