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 'icalendar'
|
||||
gem 'browser'
|
||||
|
||||
# event machine
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
after_action :set_access_control_headers
|
||||
|
@ -95,6 +95,26 @@ class ApplicationController < ActionController::Base
|
|||
session[:user_agent] = request.env['HTTP_USER_AGENT']
|
||||
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)
|
||||
|
||||
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)
|
||||
next if !model_class
|
||||
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
|
||||
next if !model_object.respond_to? :attributes
|
||||
all[model_class] = {}
|
||||
|
|
Loading…
Reference in a new issue