Init version of device logging.

This commit is contained in:
Martin Edenhofer 2015-08-17 15:25:41 +02:00
parent 94c4906264
commit 7d17849214
8 changed files with 205 additions and 1 deletions

View file

@ -55,6 +55,7 @@ gem 'net-ldap'
gem 'writeexcel'
gem 'icalendar'
gem 'browser'
# event machine
gem 'eventmachine'

View file

@ -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' )

View 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>

View file

@ -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
View 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

View 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

View 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

View file

@ -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] = {}