Merge branch 'develop' of github.com:martini/zammad into develop
This commit is contained in:
commit
89fb464915
74 changed files with 2106 additions and 596 deletions
1
Gemfile
1
Gemfile
|
@ -55,6 +55,7 @@ gem 'net-ldap'
|
|||
|
||||
gem 'writeexcel'
|
||||
gem 'icalendar'
|
||||
gem 'browser'
|
||||
|
||||
# event machine
|
||||
gem 'eventmachine'
|
||||
|
|
|
@ -210,7 +210,7 @@ class App.Controller extends Spine.Controller
|
|||
# console.log('rewrite frontendTimeUpdate', this, $(this).hasClass('escalation'))
|
||||
ui.frontendTimeUpdateItem(item)
|
||||
)
|
||||
App.Interval.set( update, 30000, 'frontendTimeUpdate', 'ui' )
|
||||
App.Interval.set( update, 61000, 'frontendTimeUpdate', 'ui' )
|
||||
|
||||
frontendTimeUpdateItem: (item) =>
|
||||
timestamp = item.data('time')
|
||||
|
|
|
@ -401,9 +401,6 @@ class App.GenericHistory extends App.ControllerModal
|
|||
# enable user popups
|
||||
@userPopups()
|
||||
|
||||
# show frontend times
|
||||
@delay( @frontendTimeUpdate, 800, 'ui-time-update' )
|
||||
|
||||
sortorder: =>
|
||||
@items = @items.reverse()
|
||||
|
||||
|
|
|
@ -274,9 +274,4 @@ class App.ControllerTable extends App.Controller
|
|||
)
|
||||
)
|
||||
|
||||
time = =>
|
||||
@frontendTimeUpdate()
|
||||
@delay(time, 80) # to show time immediately for normal tables
|
||||
@delay(time, 280) # to show time immediately for tables in modal dialog
|
||||
|
||||
table
|
||||
|
|
|
@ -51,9 +51,6 @@ class App.DashboardActivityStream extends App.Controller
|
|||
@$('.activity-entries').remove()
|
||||
@el.append html
|
||||
|
||||
# update time
|
||||
@frontendTimeUpdate()
|
||||
|
||||
renderItem: (item) ->
|
||||
html = $(App.view('dashboard/activity_stream')(
|
||||
item: item
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
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')
|
||||
|
||||
@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' )
|
|
@ -142,15 +142,15 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
searchFunction = =>
|
||||
|
||||
# use cache for search result
|
||||
if @searchResultCache[@term]
|
||||
@renderResult( @searchResultCache[@term] )
|
||||
if @searchResultCache[@query]
|
||||
@renderResult( @searchResultCache[@query] )
|
||||
|
||||
App.Ajax.request(
|
||||
id: 'search'
|
||||
type: 'GET'
|
||||
url: @apiPath + '/search'
|
||||
data:
|
||||
term: @term
|
||||
query: @query
|
||||
processData: true,
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
|
@ -158,25 +158,21 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
App.Collection.loadAssets( data.assets )
|
||||
|
||||
# cache search result
|
||||
@searchResultCache[@term] = data.result
|
||||
@searchResultCache[@query] = data.result
|
||||
|
||||
result = data.result
|
||||
for area in result
|
||||
if area.name is 'Ticket'
|
||||
area.result = []
|
||||
for id in area.ids
|
||||
ticket = App.Ticket.find( id )
|
||||
area.result.push ticket.searchResultAttributes()
|
||||
else if area.name is 'User'
|
||||
area.result = []
|
||||
for id in area.ids
|
||||
user = App.User.find( id )
|
||||
area.result.push user.searchResultAttributes()
|
||||
else if area.name is 'Organization'
|
||||
area.result = []
|
||||
for id in area.ids
|
||||
organization = App.Organization.find( id )
|
||||
area.result.push organization.searchResultAttributes()
|
||||
result = {}
|
||||
for item in data.result
|
||||
if App[item.type] && App[item.type].find
|
||||
if !result[item.type]
|
||||
result[item.type] = []
|
||||
item_object = App[item.type].find(item.id)
|
||||
if item_object.searchResultAttributes
|
||||
item_object_search_attributes = item_object.searchResultAttributes()
|
||||
result[item.type].push item_object_search_attributes
|
||||
else
|
||||
@log 'error', "No such model #{item.type.toLocaleLowerCase()}.searchResultAttributes()"
|
||||
else
|
||||
@log 'error', "No such model App.#{item.type}"
|
||||
|
||||
@renderResult(result)
|
||||
|
||||
|
@ -219,9 +215,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
removePopovers()
|
||||
|
||||
# check if search is needed
|
||||
term = @$('#global-search').val().trim()
|
||||
return if !term
|
||||
@term = term
|
||||
query = @$('#global-search').val().trim()
|
||||
return if !query
|
||||
@query = query
|
||||
@delay( searchFunction, 220, 'search' )
|
||||
)
|
||||
|
||||
|
@ -239,11 +235,11 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
return
|
||||
|
||||
# on other keys, show result
|
||||
term = @$('#global-search').val().trim()
|
||||
return if !term
|
||||
return if term is @term
|
||||
@term = term
|
||||
@$('.search').toggleClass('filled', !!@term)
|
||||
query = @$('#global-search').val().trim()
|
||||
return if !query
|
||||
return if query is @query
|
||||
@query = query
|
||||
@$('.search').toggleClass('filled', !!@query)
|
||||
@delay( searchFunction, 200, 'search' )
|
||||
)
|
||||
|
||||
|
|
|
@ -42,9 +42,6 @@ class Index extends App.ControllerContent
|
|||
sessions: data.sessions
|
||||
)
|
||||
|
||||
# show frontend times
|
||||
@frontendTimeUpdate()
|
||||
|
||||
destroy: (e) ->
|
||||
e.preventDefault()
|
||||
sessionId = $( e.target ).closest('a').data('session-id')
|
||||
|
|
|
@ -321,9 +321,6 @@ class Table extends App.Controller
|
|||
# start organization popups
|
||||
@organizationPopups()
|
||||
|
||||
# show frontend times
|
||||
@frontendTimeUpdate()
|
||||
|
||||
# start bulk action observ
|
||||
@el.find('.bulkAction').append( @bulk_form() )
|
||||
if @el.find('.table-overview').find('input[name="bulk"]:checked').length isnt 0
|
||||
|
|
|
@ -112,9 +112,6 @@ class ArticleViewItem extends App.Controller
|
|||
article: @article
|
||||
)
|
||||
|
||||
# show frontend times
|
||||
@frontendTimeUpdate()
|
||||
|
||||
# set see more option
|
||||
@setSeeMore()
|
||||
|
||||
|
|
|
@ -12,8 +12,5 @@ class App.TicketZoomMeta extends App.Controller
|
|||
isCustomer: @isRole('Customer')
|
||||
)
|
||||
|
||||
# show frontend times
|
||||
@frontendTimeUpdate()
|
||||
|
||||
release: =>
|
||||
App.Ticket.unsubscribe( @subscribeId )
|
|
@ -130,9 +130,6 @@ class App.OnlineNotificationWidget extends App.Controller
|
|||
$( App.view('widget/online_notification_content')(items: items) )
|
||||
)
|
||||
|
||||
# show frontend times
|
||||
@frontendTimeUpdate()
|
||||
|
||||
createContainer: =>
|
||||
@removeContainer()
|
||||
|
||||
|
|
|
@ -144,7 +144,6 @@ class TicketStatsList extends App.Controller
|
|||
limit: @limit
|
||||
)
|
||||
|
||||
@frontendTimeUpdate()
|
||||
@ticketPopups()
|
||||
|
||||
showAll: (e) =>
|
||||
|
|
|
@ -107,8 +107,13 @@ class App extends Spine.Controller
|
|||
# use pretty time for datetime
|
||||
else if attribute_config.tag is 'datetime'
|
||||
isHtmlEscape = true
|
||||
result = "<span class=\"humanTimeFromNow #{attribute_config.class}\" data-time=\"#{result}\">?</span>"
|
||||
#result = App.i18n.translateTimestamp(result)
|
||||
timestamp = App.i18n.translateTimestamp(result)
|
||||
escalation = false
|
||||
cssClass = attribute_config.class || ''
|
||||
if cssClass.match 'escalation'
|
||||
escalation = true
|
||||
humanTime = App.PrettyDate.humanTime(result, escalation)
|
||||
result = "<time class=\"humanTimeFromNow #{cssClass}\" data-time=\"#{result}\" data-tooltip=\"#{timestamp}\">#{humanTime}</time>"
|
||||
|
||||
if !isHtmlEscape && typeof result is 'string'
|
||||
result = App.Utils.htmlEscape(result)
|
||||
|
@ -216,6 +221,14 @@ class App extends Spine.Controller
|
|||
params.humanFileSize = ( size ) ->
|
||||
App.Utils.humanFileSize(size)
|
||||
|
||||
# define pretty/human time helper
|
||||
params.humanTime = ( time, escalation = false, cssClass = '') ->
|
||||
timestamp = App.i18n.translateTimestamp(time)
|
||||
if escalation
|
||||
cssClass += ' escalation'
|
||||
humanTime = App.PrettyDate.humanTime(time, escalation)
|
||||
"<time class=\"humanTimeFromNow #{cssClass}\" data-time=\"#{time}\" data-tooltip=\"#{timestamp}\">#{humanTime}</time>"
|
||||
|
||||
# define template
|
||||
JST["app/views/#{name}"](params)
|
||||
template
|
||||
|
|
|
@ -58,6 +58,7 @@ class _trackSingleton
|
|||
)
|
||||
|
||||
# log ajax calls
|
||||
### disabled, only needed for debugging
|
||||
$(document).bind( 'ajaxComplete', ( e, request, settings ) =>
|
||||
|
||||
# do not log ui requests
|
||||
|
@ -92,6 +93,7 @@ class _trackSingleton
|
|||
}
|
||||
)
|
||||
)
|
||||
###
|
||||
|
||||
$(window).bind(
|
||||
'beforeunload'
|
||||
|
|
|
@ -2,6 +2,7 @@ class App.Auth
|
|||
|
||||
@login: (params) ->
|
||||
App.Log.notice 'Auth', 'login', params
|
||||
params.data['fingerprint'] = App.Browser.fingerprint()
|
||||
App.Ajax.request(
|
||||
id: 'login'
|
||||
type: 'POST'
|
||||
|
@ -21,12 +22,15 @@ class App.Auth
|
|||
)
|
||||
|
||||
@loginCheck: ->
|
||||
params =
|
||||
fingerprint: App.Browser.fingerprint()
|
||||
App.Log.debug 'Auth', 'loginCheck'
|
||||
App.Ajax.request(
|
||||
id: 'login_check'
|
||||
async: false
|
||||
type: 'GET'
|
||||
type: 'POST'
|
||||
url: App.Config.get('api_path') + '/signshow'
|
||||
data: JSON.stringify(params)
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# set login (config, session, ...)
|
||||
|
|
|
@ -47,6 +47,32 @@ class App.Browser
|
|||
# allow browser
|
||||
true
|
||||
|
||||
@fingerprint: ->
|
||||
localStorage = window['localStorage']
|
||||
|
||||
# read from local storage
|
||||
if localStorage
|
||||
fingerprint = localStorage.getItem('fingerprint')
|
||||
return fingerprint if fingerprint
|
||||
|
||||
# detect fingerprint
|
||||
data = @detection()
|
||||
resolution = "#{window.screen.availWidth}x#{window.screen.availHeight}/#{window.screen.pixelDepth}"
|
||||
timezone = new Date().toString().match(/\s\(.+?\)$/)
|
||||
hashCode = (s) ->
|
||||
s.split('').reduce(
|
||||
(a,b) ->
|
||||
a=((a<<5)-a)+b.charCodeAt(0)
|
||||
a&a
|
||||
0
|
||||
)
|
||||
fingerprint = hashCode("#{data.browser.name}#{data.browser.major}#{data.os}#{resolution}#{timezone}")
|
||||
|
||||
# write to local storage
|
||||
if localStorage
|
||||
localStorage.setItem('fingerprint', fingerprint)
|
||||
fingerprint
|
||||
|
||||
@message: (data, version) ->
|
||||
new App.ControllerModal(
|
||||
head: 'Browser too old!'
|
||||
|
|
|
@ -21,6 +21,9 @@ class App.Run extends App.Controller
|
|||
# create web socket connection
|
||||
App.WebSocket.connect()
|
||||
|
||||
# start frontend time update
|
||||
@frontendTimeUpdate()
|
||||
|
||||
# start navbars
|
||||
@setupWidget( 'Navigations', 'nav', @el )
|
||||
|
||||
|
|
|
@ -115,8 +115,8 @@ class _webSocketSingleton extends App.Controller
|
|||
# logon websocket
|
||||
data =
|
||||
action: 'login'
|
||||
session:
|
||||
id: App.Session.get('id')
|
||||
session_id: App.Config.get('session_id')
|
||||
fingerprint: App.Browser.fingerprint()
|
||||
@send(data)
|
||||
|
||||
spool: =>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<span class="activity-text">
|
||||
<%= @item.created_by.displayName() %> <%- @T( @item.type ) %> <%- @T( @item.object_name ) %><% if @item.title: %> (<%= @item.title %>)<% end %>
|
||||
</span>
|
||||
<span class="activity-time humanTimeFromNow" data-time="<%- @item.created_at %>">?</span>
|
||||
<%- @humanTime(@item.created_at, false, 'activity-time') %>
|
||||
</span>
|
||||
<span class="activity-icon">
|
||||
<span class="<%- @item.cssIcon %> icon"></span>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<% for item in @items: %>
|
||||
<span class="user-popover" data-id="<%= item.created_by.id %>"><%= item.created_by.displayName() %></span> -
|
||||
<span class="humanTimeFromNow" data-time="<%- item.created_at %>">?</span>
|
||||
<%- @humanTime(item.created_at) %>
|
||||
<ul>
|
||||
<% for content in item.records: %>
|
||||
<li><%- content %></li>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</div>
|
||||
<div class="task-text">
|
||||
<a class="name ticket-popover" data-id="<%- item.id %>" href="#ticket/zoom/<%= item.id %>"><%= item.title %></a>
|
||||
<div class="time humanTimeFromNow" data-time="<%- item.created_at %>"></div>
|
||||
<%- @humanTime(item.created_at) %>
|
||||
</div>
|
||||
<div class="sidebar-list-item-delete js-delete" data-object="Ticket" data-object-id="<%= item.id %>" data-link-type="<%= type %>" data-type="remove">
|
||||
<svg class="icon icon-diagonal-cross"><use xlink:href="#icon-diagonal-cross" /></svg>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<% for area, i in @result: %>
|
||||
<% if i > 0: %> <li class="divider"></li> <% end %>
|
||||
<% for item in area.result: %>
|
||||
<% for area, items of @result: %>
|
||||
<% if done && items.length > 0: %> <li class="divider"></li> <% end %>
|
||||
<% done = true %>
|
||||
<% for item in items: %>
|
||||
<li>
|
||||
<a href="<%- item.url %>" class="nav-tab nav-tab--search <%= item.class %>" data-id="<%= item.id %>">
|
||||
<div class="nav-tab-icon">
|
||||
|
|
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') %>"<% if device.current: %>disabled<% end %>><svg class="icon-trash"><use xlink:href="#icon-trash"></use></svg></a></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<tbody>
|
||||
</table>
|
||||
|
||||
</form>
|
|
@ -18,8 +18,8 @@
|
|||
<td><% if session.data.user: %><%= session.data.user.displayName() %><% end %></td>
|
||||
<td title="<%= session.data.user_agent %>"><%= session.data.user_agent %></td>
|
||||
<td title="<%= session.data.remote_id %>"><% if session.data.geo && session.data.geo.country_name: %><%= session.data.geo.country_name %> <%= session.data.geo.city_name %><% else: %><%= session.data.remote_id %><% end %></td>
|
||||
<td><span class="humanTimeFromNow" data-time="<%- session.created_at %>">?</span></td>
|
||||
<td><span class="humanTimeFromNow" data-time="<%- session.updated_at %>">?</span></td>
|
||||
<td><%- @humanTime(session.created_at) %></td>
|
||||
<td><%- @humanTime(session.updated_at) %></td>
|
||||
<td><a href="#" data-session-id="<%- session.id %>" data-type="delete" title="<%- @Ti('Delete') %>"><svg class="icon-trash" data-type="destroy"><use xlink:href="#icon-trash"></use></svg></a></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
|
|
@ -82,4 +82,4 @@
|
|||
|
||||
<div class="js-article-actions"></div>
|
||||
|
||||
<small class="task-subline zIndex-1"><time class="humanTimeFromNow" data-time="<%- @article.created_at %>">?</time></small>
|
||||
<small class="task-subline zIndex-1"><%- @humanTime(@article.created_at) %></small>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<small class="task-subline">
|
||||
<%- @C('ticket_hook') %> <span class="ticket-number"><%- @ticket.number %></span> - <%- @T('created') %> <span class="humanTimeFromNow" data-time="<%- @ticket.created_at %>">?</span> <% if !@isCustomer && @ticket.escalation_time: %> - <%- @T('escalation') %> <span class="humanTimeFromNow escalation" data-time="<%- @ticket.escalation_time %>">?</span><% end %>
|
||||
<%- @C('ticket_hook') %> <span class="ticket-number"><%- @ticket.number %></span> - <%- @T('created') %> <%- @humanTime(@ticket.created_at) %> <% if !@isCustomer && @ticket.escalation_time: %> - <%- @T('escalation') %> <%- @humanTime(@ticket.escalation_time, true) %><% end %>
|
||||
</small>
|
|
@ -9,7 +9,7 @@
|
|||
<span class="activity-text">
|
||||
<%= item.created_by.displayName() %> <%- @T( item.type ) %> <%- @T( item.object_name ) %><% if item.title: %> (<%= item.title %>)<% end %>
|
||||
</span>
|
||||
<span class="activity-time humanTimeFromNow" data-time="<%- item.created_at %>">?</span>
|
||||
<%- @humanTime(item.created_at, false, 'activity-time') %>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
<div class="task-text">
|
||||
<a class="name ticket-popover" data-id="<%- ticket_id %>" href="<%- ticket.uiUrl() %>"><%= ticket.title %></a>
|
||||
<div class="time humanTimeFromNow" data-time="<%- ticket.created_at %>"></div>
|
||||
<%- @humanTime(ticket.created_at, false, 'time') %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
|
|
|
@ -27,10 +27,15 @@ body {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* prevent clickable <use xlink:href="#icon-abc"></use> */
|
||||
use {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 14px 0;
|
||||
color: hsl(60,1%,34%);
|
||||
|
||||
|
||||
&.subtle {
|
||||
color: hsl(60,1%,74%);
|
||||
}
|
||||
|
@ -47,6 +52,13 @@ p {
|
|||
a {
|
||||
outline: none !important;
|
||||
@extend .u-highlight;
|
||||
|
||||
&.is-disabled,
|
||||
&[disabled] {
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
opacity: .33;
|
||||
}
|
||||
}
|
||||
|
||||
a.create {
|
||||
|
|
|
@ -17,7 +17,7 @@ class ApplicationController < ActionController::Base
|
|||
before_action :set_user, :session_update
|
||||
before_action :cors_preflight_check
|
||||
|
||||
after_action :set_access_control_headers
|
||||
after_action :user_device_update, :set_access_control_headers
|
||||
after_action :trigger_events
|
||||
|
||||
# For all responses in this controller, return the CORS access control headers.
|
||||
|
@ -95,6 +95,60 @@ class ApplicationController < ActionController::Base
|
|||
session[:user_agent] = request.env['HTTP_USER_AGENT']
|
||||
end
|
||||
|
||||
# user device recent action update
|
||||
def user_device_update
|
||||
|
||||
# return if we are in switch to user mode
|
||||
return if session[:switched_from_user_id]
|
||||
|
||||
# only if user_id exists
|
||||
return if !session[:user_id]
|
||||
|
||||
# only with user device
|
||||
if !session[:user_device_id]
|
||||
if params[:fingerprint]
|
||||
return false if !user_device_log(current_user, 'session')
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# check if entry exists / only if write action
|
||||
return if request.method == 'GET' || request.method == 'OPTIONS'
|
||||
|
||||
# only update if needed
|
||||
return if session[:user_device_update_at] && session[:user_device_update_at] > Time.zone.now - 5.minutes
|
||||
session[:user_device_update_at] = Time.zone.now
|
||||
|
||||
UserDevice.action(
|
||||
session[:user_device_id],
|
||||
session[:user_agent],
|
||||
session[:remote_id],
|
||||
session[:user_id],
|
||||
)
|
||||
end
|
||||
|
||||
def user_device_log(user, type)
|
||||
|
||||
# return if we are in switch to user mode
|
||||
return true if session[:switched_from_user_id]
|
||||
|
||||
# for sessions we need the fingperprint
|
||||
if !params[:fingerprint] && type == 'session'
|
||||
render json: { error: 'Need fingerprint param!' }, status: :unprocessable_entity
|
||||
return false
|
||||
end
|
||||
|
||||
# add defice if needed
|
||||
user_device = UserDevice.add(
|
||||
request.env['HTTP_USER_AGENT'],
|
||||
request.remote_ip,
|
||||
user.id,
|
||||
params[:fingerprint],
|
||||
type,
|
||||
)
|
||||
session[:user_device_id] = user_device.id
|
||||
end
|
||||
|
||||
def authentication_check_only(auth_param)
|
||||
|
||||
logger.debug 'authentication_check'
|
||||
|
@ -104,7 +158,8 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
# already logged in, early exit
|
||||
if session.id && session[:user_id]
|
||||
userdata = User.find( session[:user_id] )
|
||||
|
||||
userdata = User.find(session[:user_id])
|
||||
current_user_set(userdata)
|
||||
|
||||
return {
|
||||
|
@ -114,31 +169,9 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
error_message = 'authentication failed'
|
||||
|
||||
# check logon session
|
||||
if params['logon_session']
|
||||
logon_session = ActiveRecord::SessionStore::Session.where( session_id: params['logon_session'] ).first
|
||||
|
||||
# set logon session user to current user
|
||||
if logon_session
|
||||
userdata = User.find( logon_session.data[:user_id] )
|
||||
current_user_set(userdata)
|
||||
|
||||
session[:persistent] = true
|
||||
|
||||
return {
|
||||
auth: true
|
||||
}
|
||||
end
|
||||
|
||||
error_message = 'no valid session, user_id'
|
||||
end
|
||||
|
||||
# check sso
|
||||
sso_userdata = User.sso(params)
|
||||
if sso_userdata
|
||||
|
||||
current_user_set(sso_userdata)
|
||||
|
||||
session[:persistent] = true
|
||||
|
||||
return {
|
||||
|
@ -154,8 +187,9 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
next if !userdata
|
||||
|
||||
# set basic auth user to current user
|
||||
current_user_set(userdata)
|
||||
user_device_log(userdata, 'basic_auth')
|
||||
|
||||
return {
|
||||
auth: true
|
||||
}
|
||||
|
@ -173,8 +207,8 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
next if !userdata
|
||||
|
||||
# set token user to current user
|
||||
current_user_set(userdata)
|
||||
user_device_log(userdata, 'token_auth')
|
||||
|
||||
return {
|
||||
auth: true
|
||||
|
@ -209,9 +243,6 @@ class ApplicationController < ActionController::Base
|
|||
return false
|
||||
end
|
||||
|
||||
# store current user id into the session
|
||||
session[:user_id] = current_user.id
|
||||
|
||||
# return auth ok
|
||||
true
|
||||
end
|
||||
|
@ -270,10 +301,14 @@ class ApplicationController < ActionController::Base
|
|||
config['timezones'][ t.name ] = diff
|
||||
}
|
||||
|
||||
# remember if we can to swich back to user
|
||||
if session[:switched_from_user_id]
|
||||
config['switch_back_to_possible'] = true
|
||||
end
|
||||
|
||||
# remember session_id for websocket logon
|
||||
config['session_id'] = session.id
|
||||
|
||||
config
|
||||
end
|
||||
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
class SearchController < ApplicationController
|
||||
before_action :authentication_check
|
||||
|
||||
# GET|POST /api/v1/search
|
||||
# GET|POST /api/v1/search/:objects
|
||||
|
||||
def search_generic
|
||||
|
||||
# enable search only for agents and admins
|
||||
if !current_user.role?(Z_ROLENAME_AGENT) && !current_user.role?(Z_ROLENAME_ADMIN)
|
||||
# enable search only for users with valid session
|
||||
if !current_user
|
||||
response_access_deny
|
||||
return true
|
||||
end
|
||||
|
@ -19,55 +20,79 @@ class SearchController < ApplicationController
|
|||
|
||||
# convert objects string into array of class names
|
||||
# e.g. user-ticket-another_object = %w( User Ticket AnotherObject )
|
||||
objects = params[:objects].split('-').map(&:camelize)
|
||||
search_tickets = objects.delete('Ticket')
|
||||
if !params[:objects]
|
||||
objects = Setting.get('models_searchable')
|
||||
else
|
||||
objects = params[:objects].split('-').map(&:camelize)
|
||||
end
|
||||
|
||||
# get priorities of result
|
||||
objects_in_order = []
|
||||
objects_in_order_hash = {}
|
||||
objects.each { |object|
|
||||
preferences = object.constantize.search_preferences(current_user)
|
||||
next if !preferences
|
||||
objects_in_order_hash[preferences[:prio]] = object
|
||||
}
|
||||
objects_in_order_hash.keys.sort.reverse.each {|prio|
|
||||
objects_in_order.push objects_in_order_hash[prio]
|
||||
}
|
||||
|
||||
# try search index backend
|
||||
assets = {}
|
||||
result = []
|
||||
if SearchIndexBackend.enabled?
|
||||
items = SearchIndexBackend.search( query, limit, objects )
|
||||
items.each { |item|
|
||||
require item[:type].to_filename
|
||||
record = Kernel.const_get( item[:type] ).find( item[:id] )
|
||||
assets = record.assets(assets)
|
||||
result.push item
|
||||
|
||||
# get direct search index based objects
|
||||
objects_with_direct_search_index = []
|
||||
objects_without_direct_search_index = []
|
||||
objects.each { |object|
|
||||
preferences = object.constantize.search_preferences(current_user)
|
||||
next if !preferences
|
||||
if preferences[:direct_search_index]
|
||||
objects_with_direct_search_index.push object
|
||||
else
|
||||
objects_without_direct_search_index.push object
|
||||
end
|
||||
}
|
||||
|
||||
# do ticket query by Ticket class to handle ticket permissions
|
||||
if search_tickets
|
||||
tickets = Ticket.search(
|
||||
query: query,
|
||||
limit: limit,
|
||||
current_user: current_user,
|
||||
)
|
||||
tickets.each do |ticket|
|
||||
assets = ticket.assets(assets)
|
||||
item = {
|
||||
id: ticket.id,
|
||||
type: 'Ticket',
|
||||
}
|
||||
# do only one query to index search backend
|
||||
if !objects_with_direct_search_index.empty?
|
||||
items = SearchIndexBackend.search( query, limit, objects_with_direct_search_index )
|
||||
items.each { |item|
|
||||
require item[:type].to_filename
|
||||
record = Kernel.const_get( item[:type] ).find( item[:id] )
|
||||
assets = record.assets(assets)
|
||||
result.push item
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# e. g. do ticket query by Ticket class to handle ticket permissions
|
||||
objects_without_direct_search_index.each { |object|
|
||||
object_result = search_generic_backend(object, query, limit, current_user, assets)
|
||||
if !object_result.empty?
|
||||
result = result.concat(object_result)
|
||||
end
|
||||
}
|
||||
|
||||
# sort order by object priority
|
||||
result_in_order = []
|
||||
objects_in_order.each { |object|
|
||||
result.each {|item|
|
||||
next if item[:type] != object
|
||||
item[:id] = item[:id].to_i
|
||||
result_in_order.push item
|
||||
}
|
||||
}
|
||||
result = result_in_order
|
||||
|
||||
else
|
||||
|
||||
# do query
|
||||
objects.each { |object|
|
||||
|
||||
found_objects = object.constantize.search(
|
||||
query: query,
|
||||
limit: limit,
|
||||
current_user: current_user,
|
||||
)
|
||||
|
||||
found_objects.each do |found_object|
|
||||
item = {
|
||||
id: found_object.id,
|
||||
type: found_object.class.to_s
|
||||
}
|
||||
result.push item
|
||||
assets = found_object.assets(assets)
|
||||
objects_in_order.each { |object|
|
||||
object_result = search_generic_backend(object, query, limit, current_user, assets)
|
||||
if !object_result.empty?
|
||||
result = result.concat(object_result)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -78,84 +103,23 @@ class SearchController < ApplicationController
|
|||
}
|
||||
end
|
||||
|
||||
# GET /api/v1/search
|
||||
def search
|
||||
private
|
||||
|
||||
# get params
|
||||
query = params[:term]
|
||||
limit = params[:limit] || 10
|
||||
|
||||
assets = {}
|
||||
result = []
|
||||
objects = %w( Ticket User Organization )
|
||||
if SearchIndexBackend.enabled?
|
||||
|
||||
# to ticket search in serparate call
|
||||
objects.delete('Ticket')
|
||||
|
||||
# to query search index backend (excluse tickets here, see below)
|
||||
found_objects = {}
|
||||
items = SearchIndexBackend.search( query, limit, objects )
|
||||
items.each { |item|
|
||||
require item[:type].to_filename
|
||||
record = Kernel.const_get( item[:type] ).find( item[:id] )
|
||||
assets = record.assets(assets)
|
||||
|
||||
found_objects[ item[:type] ] ||= []
|
||||
found_objects[ item[:type] ].push item[:id]
|
||||
}
|
||||
|
||||
# do ticket query by Ticket class to handle ticket permissions
|
||||
tickets = Ticket.search(
|
||||
query: query,
|
||||
limit: limit,
|
||||
current_user: current_user,
|
||||
)
|
||||
tickets.each do |ticket|
|
||||
found_objects[ 'Ticket' ] ||= []
|
||||
found_objects[ 'Ticket' ].push ticket.id
|
||||
end
|
||||
|
||||
# generate whole result
|
||||
found_objects.each { |object, object_ids|
|
||||
|
||||
data = {
|
||||
name: object,
|
||||
ids: object_ids,
|
||||
}
|
||||
result.push data
|
||||
}
|
||||
else
|
||||
|
||||
objects.each { |object|
|
||||
|
||||
found_objects = object.constantize.search(
|
||||
query: query,
|
||||
limit: limit,
|
||||
current_user: current_user,
|
||||
)
|
||||
|
||||
object_ids = []
|
||||
found_objects.each do |found_object|
|
||||
object_ids.push found_object.id
|
||||
assets = found_object.assets(assets)
|
||||
end
|
||||
|
||||
next if object_ids.empty?
|
||||
|
||||
data = {
|
||||
name: object,
|
||||
ids: object_ids,
|
||||
}
|
||||
result.push data
|
||||
def search_generic_backend(object, query, limit, current_user, assets)
|
||||
found_objects = object.constantize.search(
|
||||
query: query,
|
||||
limit: limit,
|
||||
current_user: current_user,
|
||||
)
|
||||
result = []
|
||||
found_objects.each do |found_object|
|
||||
item = {
|
||||
id: found_object.id,
|
||||
type: found_object.class.to_s
|
||||
}
|
||||
result.push item
|
||||
assets = found_object.assets(assets)
|
||||
end
|
||||
|
||||
# return result
|
||||
render json: {
|
||||
assets: assets,
|
||||
result: result,
|
||||
}
|
||||
result
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -30,6 +30,9 @@ class SessionsController < ApplicationController
|
|||
# set session user
|
||||
current_user_set(user)
|
||||
|
||||
# log device
|
||||
return if !user_device_log(user, 'session')
|
||||
|
||||
# log new session
|
||||
user.activity_stream_log( 'session started', user.id, true )
|
||||
|
||||
|
@ -42,18 +45,6 @@ class SessionsController < ApplicationController
|
|||
# get models
|
||||
models = SessionHelper.models(user)
|
||||
|
||||
# check logon session
|
||||
logon_session_key = nil
|
||||
if params['logon_session']
|
||||
logon_session_key = Digest::MD5.hexdigest( rand(999_999).to_s + Time.zone.now.to_s )
|
||||
# session = ActiveRecord::SessionStore::Session.create(
|
||||
# :session_id => logon_session_key,
|
||||
# :data => {
|
||||
# :user_id => user['id']
|
||||
# }
|
||||
# )
|
||||
end
|
||||
|
||||
# sessions created via this
|
||||
# controller are persistent
|
||||
session[:persistent] = true
|
||||
|
@ -62,10 +53,10 @@ class SessionsController < ApplicationController
|
|||
render status: :created,
|
||||
json: {
|
||||
session: user,
|
||||
config: config_frontend,
|
||||
models: models,
|
||||
collections: collections,
|
||||
assets: assets,
|
||||
logon_session: logon_session_key,
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -78,14 +69,6 @@ class SessionsController < ApplicationController
|
|||
user_id = session[:user_id]
|
||||
end
|
||||
|
||||
# check logon session
|
||||
if params['logon_session']
|
||||
session = SessionHelper.get( params['logon_session'] )
|
||||
if session
|
||||
user_id = session.data[:user_id]
|
||||
end
|
||||
end
|
||||
|
||||
if !user_id
|
||||
# get models
|
||||
models = SessionHelper.models()
|
||||
|
@ -96,7 +79,7 @@ class SessionsController < ApplicationController
|
|||
models: models,
|
||||
collections: {
|
||||
Locale.to_app_model => Locale.where( active: true )
|
||||
}
|
||||
},
|
||||
}
|
||||
return
|
||||
end
|
||||
|
@ -105,6 +88,9 @@ class SessionsController < ApplicationController
|
|||
# subsequent requests
|
||||
user = User.find( user_id )
|
||||
|
||||
# log device
|
||||
return if !user_device_log(user, 'session')
|
||||
|
||||
# auto population of default collections
|
||||
collections, assets = SessionHelper.default_collections(user)
|
||||
|
||||
|
@ -117,10 +103,10 @@ class SessionsController < ApplicationController
|
|||
# return current session
|
||||
render json: {
|
||||
session: user,
|
||||
config: config_frontend,
|
||||
models: models,
|
||||
collections: collections,
|
||||
assets: assets,
|
||||
config: config_frontend,
|
||||
}
|
||||
end
|
||||
|
||||
|
|
44
app/controllers/user_devices_controller.rb
Normal file
44
app/controllers/user_devices_controller.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class UserDevicesController < ApplicationController
|
||||
before_action :authentication_check
|
||||
|
||||
def index
|
||||
devices = UserDevice.where(user_id: current_user.id).order('created_at DESC')
|
||||
devices_full = []
|
||||
devices.each {|device|
|
||||
attributes = device.attributes
|
||||
if device.location_details['city_name'] && !device.location_details['city_name'].empty?
|
||||
attributes['location'] += ", #{device.location_details['city_name']}"
|
||||
end
|
||||
attributes.delete('created_at')
|
||||
attributes.delete('device_details')
|
||||
attributes.delete('location_details')
|
||||
|
||||
if session[:user_device_id] == device.id
|
||||
attributes['current'] = true
|
||||
end
|
||||
devices_full.push attributes
|
||||
}
|
||||
model_index_render_result(devices_full)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
||||
# find device
|
||||
user_device = UserDevice.find_by(user_id: current_user.id, id: params[:id])
|
||||
|
||||
# delete device and session's
|
||||
if user_device
|
||||
SessionHelper.list.each {|session|
|
||||
next if !session.data['user_id']
|
||||
next if !session.data['user_device_id']
|
||||
next if session.data['user_device_id'] != user_device.id
|
||||
SessionHelper.destroy( session.id )
|
||||
}
|
||||
user_device.destroy
|
||||
end
|
||||
render json: {}, status: :ok
|
||||
end
|
||||
|
||||
end
|
|
@ -5,6 +5,33 @@ class Organization
|
|||
|
||||
=begin
|
||||
|
||||
search organizations preferences
|
||||
|
||||
result = Organization.search_preferences(user_model)
|
||||
|
||||
returns if user has permissions to search
|
||||
|
||||
result = {
|
||||
prio: 1000,
|
||||
direct_search_index: true
|
||||
}
|
||||
|
||||
returns if user has no permissions to search
|
||||
|
||||
result = false
|
||||
|
||||
=end
|
||||
|
||||
def search_preferences(current_user)
|
||||
return false if !current_user.role?('Agent') && !current_user.role?(Z_ROLENAME_ADMIN)
|
||||
{
|
||||
prio: 1000,
|
||||
direct_search_index: true,
|
||||
}
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
search organizations
|
||||
|
||||
result = Organization.search(
|
||||
|
@ -27,7 +54,7 @@ returns
|
|||
current_user = params[:current_user]
|
||||
|
||||
# enable search only for agents and admins
|
||||
return [] if !current_user.role?('Agent') && !current_user.role?(Z_ROLENAME_ADMIN)
|
||||
return [] if !search_preferences(current_user)
|
||||
|
||||
# try search index backend
|
||||
if SearchIndexBackend.enabled?
|
||||
|
|
|
@ -3,6 +3,32 @@ module Ticket::Search
|
|||
|
||||
=begin
|
||||
|
||||
search tickets preferences
|
||||
|
||||
result = Ticket.search_preferences(user_model)
|
||||
|
||||
returns if user has permissions to search
|
||||
|
||||
result = {
|
||||
prio: 3000,
|
||||
direct_search_index: false
|
||||
}
|
||||
|
||||
returns if user has no permissions to search
|
||||
|
||||
result = false
|
||||
|
||||
=end
|
||||
|
||||
def search_preferences(_current_user)
|
||||
{
|
||||
prio: 3000,
|
||||
direct_search_index: false,
|
||||
}
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
search tickets via search index
|
||||
|
||||
result = Ticket.search(
|
||||
|
@ -53,7 +79,7 @@ returns
|
|||
|
||||
=end
|
||||
|
||||
def search (params)
|
||||
def search(params)
|
||||
|
||||
# get params
|
||||
query = params[:query]
|
||||
|
|
|
@ -15,7 +15,11 @@ load translations from online
|
|||
=end
|
||||
|
||||
def self.load
|
||||
Locale.where(active: true).each {|locale|
|
||||
locales = Locale.where(active: true)
|
||||
if Rails.env.test?
|
||||
locales = Locale.where(active: true, locale: ['en-us', 'de-de'])
|
||||
end
|
||||
locales.each {|locale|
|
||||
url = "https://i18n.zammad.com/api/v1/translations/#{locale.locale}"
|
||||
if !UserInfo.current_user_id
|
||||
UserInfo.current_user_id = 1
|
||||
|
|
|
@ -5,6 +5,33 @@ class User
|
|||
|
||||
=begin
|
||||
|
||||
search user preferences
|
||||
|
||||
result = User.search_preferences(user_model)
|
||||
|
||||
returns if user has permissions to search
|
||||
|
||||
result = {
|
||||
prio: 1000,
|
||||
direct_search_index: true
|
||||
}
|
||||
|
||||
returns if user has no permissions to search
|
||||
|
||||
result = false
|
||||
|
||||
=end
|
||||
|
||||
def search_preferences(current_user)
|
||||
return false if !current_user.role?('Agent') && !current_user.role?(Z_ROLENAME_ADMIN)
|
||||
{
|
||||
prio: 2000,
|
||||
direct_search_index: true,
|
||||
}
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
search user
|
||||
|
||||
result = User.search(
|
||||
|
@ -27,7 +54,7 @@ returns
|
|||
current_user = params[:current_user]
|
||||
|
||||
# enable search only for agents and admins
|
||||
return [] if !current_user.role?('Agent') && !current_user.role?(Z_ROLENAME_ADMIN)
|
||||
return [] if !search_preferences(current_user)
|
||||
|
||||
# try search index backend
|
||||
if SearchIndexBackend.enabled?
|
||||
|
|
191
app/models/user_device.rb
Normal file
191
app/models/user_device.rb
Normal file
|
@ -0,0 +1,191 @@
|
|||
# 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
|
||||
|
||||
user_device = 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,
|
||||
'fingerprintABC123',
|
||||
'session', # session|basic_auth|token_auth|sso
|
||||
)
|
||||
|
||||
=end
|
||||
|
||||
def self.add(user_agent, ip, user_id, fingerprint, type)
|
||||
|
||||
# get location info
|
||||
location_details = Service::GeoIp.location(ip)
|
||||
location = location_details['country_name']
|
||||
|
||||
# find device by fingerprint
|
||||
if fingerprint
|
||||
user_device = UserDevice.find_by(
|
||||
user_id: user_id,
|
||||
fingerprint: fingerprint,
|
||||
location: location,
|
||||
)
|
||||
return action(user_device.id, user_agent, ip, user_id) if user_device
|
||||
end
|
||||
|
||||
# for basic_auth|token_auth search for user agent
|
||||
if type == 'basic_auth' || type == 'token_auth'
|
||||
user_device = UserDevice.find_by(
|
||||
user_id: user_id,
|
||||
user_agent: user_agent,
|
||||
location: location,
|
||||
)
|
||||
return action(user_device.id, user_agent, ip, user_id) if user_device
|
||||
end
|
||||
|
||||
# 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 = ''
|
||||
if browser[:plattform] && browser[:plattform] != 'Other'
|
||||
name = browser[:plattform]
|
||||
end
|
||||
if browser[:name] && browser[:name] != 'Other'
|
||||
if name && !name.empty?
|
||||
name += ', '
|
||||
end
|
||||
name += browser[:name]
|
||||
end
|
||||
|
||||
# if not identified, use user agent
|
||||
if !name || name == '' || name == 'Other, Other' || name == 'Other'
|
||||
name = user_agent
|
||||
browser[:name] = user_agent
|
||||
end
|
||||
|
||||
# check if exists
|
||||
user_device = self.find_by(
|
||||
user_id: user_id,
|
||||
os: browser[:plattform],
|
||||
browser: browser[:name],
|
||||
location: location,
|
||||
)
|
||||
|
||||
if user_device
|
||||
return action(user_device.id, user_agent, ip, user_id) if user_device
|
||||
end
|
||||
|
||||
# create new device
|
||||
user_device = self.create(
|
||||
user_id: user_id,
|
||||
name: name,
|
||||
os: browser[:plattform],
|
||||
browser: browser[:name],
|
||||
location: location,
|
||||
device_details: browser,
|
||||
location_details: location_details,
|
||||
user_agent: user_agent,
|
||||
ip: ip,
|
||||
fingerprint: fingerprint,
|
||||
)
|
||||
|
||||
# send notification if needed
|
||||
user_devices = UserDevice.where(user_id: user_id).count
|
||||
if user_devices >= 2
|
||||
user_device.send_notification
|
||||
end
|
||||
|
||||
user_device
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
log user device action
|
||||
|
||||
UserDevice.action(
|
||||
user_device_id,
|
||||
'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.action(user_device_id, user_agent, ip, user_id)
|
||||
user_device = UserDevice.find(user_device_id)
|
||||
|
||||
# update location if needed
|
||||
if user_device.ip != ip
|
||||
user_device.ip = ip
|
||||
location_details = Service::GeoIp.location(ip)
|
||||
user_device.location_details = location_details
|
||||
|
||||
location = location_details['country_name']
|
||||
user_device.location = location
|
||||
end
|
||||
|
||||
# update attributes
|
||||
user_device.save
|
||||
user_device
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
send new user device info
|
||||
|
||||
user_device = UserDevice.find(id)
|
||||
|
||||
user_device.send_notification
|
||||
|
||||
=end
|
||||
|
||||
def send_notification
|
||||
user = User.find(user_id)
|
||||
|
||||
# send mail
|
||||
data = {}
|
||||
data[:subject] = '#{config.product_name} signin detected from a new device'
|
||||
data[:body] = 'Hi #{user.firstname},
|
||||
|
||||
it looks like you signed into your #{config.product_name} account using a new device on "#{user_device.created_at}":
|
||||
|
||||
Your Location: #{user_device.location}
|
||||
Your IP: #{user_device.ip}
|
||||
|
||||
Your device has been added to your list of known devices, which you can view here:
|
||||
|
||||
#{config.http_type}://#{config.fqdn}/#profile/devices
|
||||
|
||||
If this wasn\'t you, remove the device, changing your account password, and contacting your administrator. Somebody might have gained unauthorized access to your account.
|
||||
|
||||
Your #{config.product_name} Team'
|
||||
|
||||
# prepare subject & body
|
||||
[:subject, :body].each { |key|
|
||||
data[key.to_sym] = NotificationFactory.build(
|
||||
locale: user.preferences[:locale],
|
||||
string: data[key.to_sym],
|
||||
objects: {
|
||||
user_device: self,
|
||||
user: user,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
# send notification
|
||||
NotificationFactory.send(
|
||||
recipient: user,
|
||||
subject: data[:subject],
|
||||
body: data[:body]
|
||||
)
|
||||
end
|
||||
end
|
8
config/initializers/models_searchable.rb
Normal file
8
config/initializers/models_searchable.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
# update settings for searchable models
|
||||
if ActiveRecord::Base.connection.tables.include?('settings')
|
||||
models_current = Models.searchable.map(&:to_s)
|
||||
models_config = Setting.get('models_searchable')
|
||||
if models_config && models_current != models_config
|
||||
Setting.set('models_searchable', models_current)
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Your secret key for verifying the integrity of signed cookies.
|
||||
# If you change this key, all old signed cookies will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
Zammad::Application.config.secret_token = '7e2713d027d0cd980171f483a37bff6304f7e994f07f337b6130fec20c2e9c8f8093a9fc70128f13fe9d006f7f785064c8e612e92c6171cb35ba675b626f633d'
|
|
@ -9,7 +9,7 @@ Zammad::Application.routes.draw do
|
|||
|
||||
# sessions
|
||||
match api_path + '/signin', to: 'sessions#create', via: :post
|
||||
match api_path + '/signshow', to: 'sessions#show', via: :get
|
||||
match api_path + '/signshow', to: 'sessions#show', via: [:get, :post]
|
||||
match api_path + '/signout', to: 'sessions#destroy', via: [:get, :delete]
|
||||
|
||||
match api_path + '/sessions/switch/:id', to: 'sessions#switch_to_user', via: :get
|
||||
|
|
|
@ -2,8 +2,6 @@ Zammad::Application.routes.draw do
|
|||
api_path = Rails.configuration.api_path
|
||||
|
||||
# search
|
||||
match api_path + '/search', to: 'search#search', via: [:get, :post]
|
||||
|
||||
# search_generic
|
||||
match api_path + '/search', to: 'search#search_generic', via: [:get, :post]
|
||||
match api_path + '/search/:objects', to: 'search#search_generic', via: [:get, :post]
|
||||
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
|
8
config/secrets.yml
Normal file
8
config/secrets.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
development:
|
||||
secret_key_base: secret_key_base_is_not_used
|
||||
|
||||
test:
|
||||
secret_key_base: secret_key_base_is_not_used
|
||||
|
||||
production:
|
||||
secret_key_base: secret_key_base_is_not_used
|
15
db/migrate/20150816000001_update_model_searchable.rb
Normal file
15
db/migrate/20150816000001_update_model_searchable.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class UpdateModelSearchable < ActiveRecord::Migration
|
||||
def up
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Define searchable models.',
|
||||
name: 'models_searchable',
|
||||
area: 'Models::Base',
|
||||
description: 'Define the models which can be searched for.',
|
||||
options: {},
|
||||
state: [],
|
||||
frontend: false,
|
||||
)
|
||||
|
||||
end
|
||||
end
|
27
db/migrate/20150817000001_create_user_devices.rb
Normal file
27
db/migrate/20150817000001_create_user_devices.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
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 :location, limit: 150, null: true
|
||||
t.string :device_details, limit: 2500, null: true
|
||||
t.string :location_details, limit: 2500, null: true
|
||||
t.string :fingerprint, limit: 160, null: true
|
||||
t.string :user_agent, limit: 250, null: true
|
||||
t.string :ip, limit: 160, null: true
|
||||
t.timestamps
|
||||
end
|
||||
add_index :user_devices, [:user_id]
|
||||
add_index :user_devices, [:os, :browser, :location]
|
||||
add_index :user_devices, [:fingerprint]
|
||||
add_index :user_devices, [:updated_at]
|
||||
add_index :user_devices, [:created_at]
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :user_devices
|
||||
end
|
||||
end
|
10
db/seeds.rb
10
db/seeds.rb
|
@ -1187,6 +1187,16 @@ Setting.create_if_not_exists(
|
|||
frontend: true
|
||||
)
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Define searchable models.',
|
||||
name: 'models_searchable',
|
||||
area: 'Models::Base',
|
||||
description: 'Define the models which can be searched for.',
|
||||
options: {},
|
||||
state: [],
|
||||
frontend: false,
|
||||
)
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Default Screen',
|
||||
name: 'default_controller',
|
||||
|
|
|
@ -10,11 +10,11 @@ get list of models
|
|||
returns
|
||||
|
||||
{
|
||||
'Some::Classname1' => {
|
||||
Some::Classname1 => {
|
||||
attributes: ['id', 'name', '...']
|
||||
reflections: ...model.reflections...
|
||||
},
|
||||
'Some::Classname2' => {
|
||||
Some::Classname2 => {
|
||||
attributes: ['id', 'name', '...']
|
||||
reflections: ...model.reflections...
|
||||
},
|
||||
|
@ -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] = {}
|
||||
|
@ -49,6 +52,28 @@ returns
|
|||
|
||||
=begin
|
||||
|
||||
get list of searchable models
|
||||
|
||||
result = Models.searchable
|
||||
|
||||
returns
|
||||
|
||||
[Model1, Model2, Model3]
|
||||
|
||||
=end
|
||||
|
||||
def self.searchable
|
||||
models = []
|
||||
all.each {|model_class, options|
|
||||
next if !model_class
|
||||
next if !model_class.respond_to? :search_preferences
|
||||
models.push model_class
|
||||
}
|
||||
models
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
get reference list of a models
|
||||
|
||||
result = Models.references('User', 2)
|
||||
|
|
|
@ -150,7 +150,7 @@ return search result
|
|||
|
||||
=end
|
||||
|
||||
def self.search( query, _limit = 10, index = nil, query_extention = {} )
|
||||
def self.search( query, limit = 10, index = nil, query_extention = {} )
|
||||
return [] if !query
|
||||
|
||||
url = build_url()
|
||||
|
@ -166,7 +166,7 @@ return search result
|
|||
end
|
||||
data = {}
|
||||
data['from'] = 0
|
||||
data['size'] = 10
|
||||
data['size'] = limit
|
||||
data['sort'] =
|
||||
[
|
||||
{
|
||||
|
|
|
@ -37,7 +37,7 @@ module SessionHelper
|
|||
end
|
||||
|
||||
def self.get(id)
|
||||
ActiveRecord::SessionStore::Session.where( id: id ).first
|
||||
ActiveRecord::SessionStore::Session.find_by( id: id )
|
||||
end
|
||||
|
||||
def self.list(limit = 10_000)
|
||||
|
@ -45,7 +45,7 @@ module SessionHelper
|
|||
end
|
||||
|
||||
def self.destroy(id)
|
||||
session = ActiveRecord::SessionStore::Session.where( id: id ).first
|
||||
session = ActiveRecord::SessionStore::Session.find_by( id: id )
|
||||
return if !session
|
||||
session.destroy
|
||||
end
|
||||
|
|
|
@ -42,9 +42,14 @@ namespace :searchindex do
|
|||
task :reload, [:opts] => :environment do |_t, _args|
|
||||
|
||||
puts 'reload data...'
|
||||
User.search_index_reload
|
||||
Organization.search_index_reload
|
||||
Ticket.search_index_reload
|
||||
Models.searchable.each {|model_class|
|
||||
puts " reload #{model_class}"
|
||||
started_at = Time.zone.now
|
||||
puts " - started at #{started_at}"
|
||||
model_class.search_index_reload
|
||||
took = Time.zone.now - started_at
|
||||
puts " - took #{took.to_i} seconds"
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,26 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>The page you were looking for doesn't exist (404)</title>
|
||||
<style type="text/css">
|
||||
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
||||
div.dialog {
|
||||
width: 25em;
|
||||
padding: 0 4em;
|
||||
margin: 4em auto 0 auto;
|
||||
border: 1px solid #ccc;
|
||||
border-right-color: #999;
|
||||
border-bottom-color: #999;
|
||||
}
|
||||
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
||||
</style>
|
||||
</head>
|
||||
<html class="dark">
|
||||
<meta charset="utf-8">
|
||||
<title>404: Not Found</title>
|
||||
<link rel="stylesheet" href="/assets/error/style.css">
|
||||
|
||||
<body>
|
||||
<!-- This file lives in public/404.html -->
|
||||
<div class="dialog">
|
||||
<h1>The page you were looking for doesn't exist.</h1>
|
||||
<p>You may have mistyped the address or the page may have moved.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<h1>404: Requested Page was not found.</h1>
|
||||
<div class="error-image" style="background-image: url(/assets/error/error-2.svg)"></div>
|
||||
<p>Sorry, but the Phoenix is not able to find your page. Try checking the URL for errors.</p>
|
||||
</html>
|
|
@ -1,26 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>The change you wanted was rejected (422)</title>
|
||||
<style type="text/css">
|
||||
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
||||
div.dialog {
|
||||
width: 25em;
|
||||
padding: 0 4em;
|
||||
margin: 4em auto 0 auto;
|
||||
border: 1px solid #ccc;
|
||||
border-right-color: #999;
|
||||
border-bottom-color: #999;
|
||||
}
|
||||
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
||||
</style>
|
||||
</head>
|
||||
<html class="dark">
|
||||
<meta charset="utf-8">
|
||||
<title>422: Not Found</title>
|
||||
<link rel="stylesheet" href="/assets/error/style.css">
|
||||
|
||||
<body>
|
||||
<!-- This file lives in public/422.html -->
|
||||
<div class="dialog">
|
||||
<h1>The change you wanted was rejected.</h1>
|
||||
<p>Maybe you tried to change something you didn't have access to.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<h1>422: The change you wanted was rejected.</h1>
|
||||
<div class="error-image" style="background-image: url(/assets/error/error-1.svg)"></div>
|
||||
<p>Maybe you tried to change something you didn't have access to.</p>
|
||||
</html>
|
|
@ -1,25 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>We're sorry, but something went wrong (500)</title>
|
||||
<style type="text/css">
|
||||
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
||||
div.dialog {
|
||||
width: 25em;
|
||||
padding: 0 4em;
|
||||
margin: 4em auto 0 auto;
|
||||
border: 1px solid #ccc;
|
||||
border-right-color: #999;
|
||||
border-bottom-color: #999;
|
||||
}
|
||||
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
||||
</style>
|
||||
</head>
|
||||
<html class="dark">
|
||||
<meta charset="utf-8">
|
||||
<title>500: Something went wrong</title>
|
||||
<link rel="stylesheet" href="/assets/error/style.css">
|
||||
|
||||
<body>
|
||||
<!-- This file lives in public/500.html -->
|
||||
<div class="dialog">
|
||||
<h1>We're sorry, but something went wrong.</h1>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<h1>500: We're sorry, but something went wrong.</h1>
|
||||
<div class="error-image" style="background-image: url(/assets/error/error-2.svg)"></div>
|
||||
<p>We're sorry, but something went wrong.</p>
|
||||
</html>
|
1
public/assets/error/error-1.svg
Normal file
1
public/assets/error/error-1.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 750 650" enable-background="new 0 0 750 650"><path fill="#ceb249" d="m402.63 286.83l8.93 173.24-64-218.41z"/><path fill="#f8e192" d="m402.63 286.83l-54.69-.1 121.23 107.4z"/><path fill="#e09b16" d="m406.93 210.14l-40.31 17.79 11.17 89.38 24.31-37.54z"/><path fill="#f3d14f" d="m402.63 286.83l-32.25-53.9-19.02 55.94.23 207.07z"/><path opacity=".15" fill="#fff" d="m402.63 286.83l2.86 50.87-57.55-50.97"/><path fill="#e09b16" d="m406.25 122.5l-31.25-28.75-31.25 28.75-39.16 51.28 40.37 109.22h30.04 30.04l40.37-109.22z"/><path fill="#3f2e20" d="m442.5 227.5l-67.5 20-67.5-20 67.5-15z"/><g fill="#dfe0e1"><ellipse cx="409.5" cy="229.5" rx="22.5" ry="30"/><ellipse cx="345.5" cy="227.5" rx="22.5" ry="30"/></g><ellipse fill="#f8f9fa" cx="375" cy="220.5" rx="22.5" ry="30"/><path fill="#5d3d1b" d="m405.04 283l37.46-55.5-67.5 20-67.5-20 37.46 55.5z"/><path fill="#835c3a" d="m375 247.5l-67.5-20 37.46 55.5h30.04v-35.5"/><path fill="#704c2a" d="m442.5 227.5l-67.5 20v35.5h30.04z"/><g fill="#389cd8"><path d="m552.5 283h-130l-2.5 10h132.5 5v-5c0-2.75-2.25-5-5-5"/><path d="m347.5 283h60v10h-60z"/></g><path fill="#1e5a6e" d="m307.07 248.12l9.67-41.11 56.27 81.16z"/><path fill="#c8431c" d="m343.75 122.5l19.33 71.58 43.17-71.58z"/><path fill="#af2527" d="m375 190.4l-31.25-67.9h62.5"/><path fill="#cb4f83" d="m375 93.75l-31.25 28.75 31.25 36.25 31.25-36.25z"/><path fill="#c8431c" d="m375 93.75l.01 28.75 12.72-59.45z"/><path fill="#af2527" d="m375 93.75l.01 28.75 24.05-59.45z"/><path fill="#3aa3c2" d="m406.25 122.5l39.16 51.28"/><path opacity=".15" fill="#fff" d="m373.01 288.17l-65.94-40.05 3.33-18.51z"/><path fill="#7db3ca" d="m343.75 122.5l-36.68 125.62-2.48-74.34z"/><g fill="#c8431c"><path d="m407.5 303l5-20h-10z"/><path d="m397.5 303l5-20h-10z"/></g><path fill="#cb4f83" d="m412.5 283h-20l4-8h12z"/><path fill="#c8431c" d="m402.5 305l5-24h-10z"/><path opacity=".15" fill="#fff" d="m402.5 305l5-24h-10z"/><g fill="#c8431c"><path d="m342.5 303l-5-20h10z"/><path d="m352.5 303l-5-20h10z"/></g><path fill="#cb4f83" d="m337.5 283h20l-4-8h-12z"/><path fill="#c8431c" d="m347.5 305l-5-24h10z"/><path opacity=".15" fill="#fff" d="m347.5 305l-5-24h10z"/><path fill="#c7e4f1" d="m406.25 122.5l-91.1 197.92 130.26-146.64z"/><path fill="#3aa3c2" d="m315.15 320.42l84.18-132.07 6.92-65.85"/><path opacity=".15" fill="#fff" d="m406.25 122.5l39.16 51.28-46.08 14.57z"/><path fill="#389cd8" d="m197.5 283h125l-4.5 10h-120.5-5v-5c0-2.75 2.25-5 5-5"/><g fill="none" stroke="#a1a4a7" stroke-width="2" stroke-miterlimit="10"><path d="m472.5 247.5v-40"/><path d="m482.5 247.5v-40"/></g></svg>
|
After Width: | Height: | Size: 2.6 KiB |
1
public/assets/error/error-2.svg
Normal file
1
public/assets/error/error-2.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 750 650" enable-background="new 0 0 750 650"><defs><use id="1" opacity=".5" xlink:href="#2"/><path id="2" d="m340 259.82h70v60h-70z"/><clipPath id="0"><use xlink:href="#1"/></clipPath></defs><path fill="#3aa3c2" d="m503.63 133.93l-87.89 145.47-6.4-37.56z"/><path fill="#67878f" d="m483.86 149.06l89.12 56.91-116.42-35.39z"/><path fill="#1e5a6e" d="m483.86 149.06l25.52 102.55-52.82-81.03z"/><path opacity=".15" fill="#fff" d="m475.6 162.83l9.34-9.61 24.44 98.39z"/><path fill="#ceb249" d="m433.17 215.46l60.57-162.56-126.68 189.09z"/><path fill="#f8e192" d="m433.17 215.46l-52.2-16.34 147.9-66.01z"/><path fill="#7db3ca" d="m413.39 244.36l55.36-112.95-36.67 138.54z"/><path fill="#f3d14f" d="m433.17 215.46l-46.96 41.72-5.24-58.06 66.35-198.44z"/><path fill="#3aa3c2" d="m468.75 131.41l98.3-16.15-117.4 55.09z"/><path fill="#c7e4f1" d="m322.42 244.31l146.33-112.9-74.78 152.51z"/><g fill="#dc8c18"><path d="m493.75 271.32h-25v-30z"/><path d="m256 271.32h25v-30z"/></g><path fill="#a27c4c" d="m387.5 614.32l-25 35v-270h25z"/><path fill="#dc8c18" d="m452.5 374.32c0 2.75-2.25 5-5 5h-145c-2.75 0-5-2.25-5-5v-15c0-2.75 2.25-5 5-5h145c2.75 0 5 2.25 5 5v15"/><path fill="#e7b141" d="m379.77 198.83c-2.622-.828-6.913-.828-9.536 0l-85.46 26.988c-2.623.828-4.768 3.756-4.768 6.506v130c0 2.75 2.25 5 5 5h180c2.75 0 5-2.25 5-5v-130c0-2.75-2.146-5.678-4.768-6.506l-85.46-26.988"/><path opacity=".15" fill="#fff" d="m375 218.57l-71.25 22.5v110h142.5v-110z"/><g fill="#dc9118"><path opacity=".2" d="m446.25 241.07v110l18.75 16.25c2.75 0 5-2.25 5-5v-130c0-2.75-2.146-5.678-4.768-6.506l-18.982 15.256"/><path opacity=".2" d="m284.77 225.81c-2.621.828-4.768 3.756-4.768 6.506v130c0 2.75 2.25 5 5 5l18.75-16.25v-110l-18.982-15.256"/><path opacity=".9" d="m303.75 351.07l-18.75 16.25h90v-16.25z"/><path opacity=".65" d="m370.23 198.83l-85.46 26.988 18.982 15.256 71.25-22.5v-20.365c-1.729 0-3.457.207-4.767.621"/><path opacity=".6" d="m446.25 351.07l18.75 16.25h-90v-16.25z"/><path opacity=".9" d="m379.77 198.83l85.46 26.988-18.982 15.256-71.25-22.5v-20.365c1.728 0 3.456.207 4.767.621"/></g><g fill="#36af6a"><path d="m347.5 604.32h-150c-2.75 0-5 2.25-5 5v5h5 150 5v-10h-5"/><path d="m402.5 604.32h150c2.75 0 5 2.25 5 5v5h-5-150-5v-10h5"/></g><path fill="#67878f" d="m422.5 324.82c0 2.75-2.25 5-5 5h-85c-2.75 0-5-2.25-5-5v-70c0-2.75 2.25-5 5-5h85c2.75 0 5 2.25 5 5v70"/><ellipse fill="#444a4f" cx="374.94" cy="340.48" rx="5" ry="6"/><use fill="#7db3ca" xlink:href="#2"/><path opacity=".3" fill="#1e5a6e" d="m422.5 254.82c0-2.75-2.25-5-5-5h-85c-2.75 0-5 2.25-5 5l12.5 5h70l12.5-5m-95 70c0 2.75 2.25 5 5 5h85c2.75 0 5-2.25 5-5l-12.5-5h-70l-12.5 5"/><g opacity=".5"><g clip-path="url(#0)"><path fill="#c8431c" d="m413.81 318.97l6.71-81.51 41.11-41.34z"/><path fill="#e09b16" d="m376.48 236.01l44.04 1.45 28.69-85.39-38.18 23.3z"/><g fill="#c8431c"><path d="m333.56 322.45l15.12-12.04 36.77 9.6z"/><path d="m355.04 298.93l41.81-65.34-3.03 25.14"/></g><path opacity=".15" fill="#fff" d="m313.46 233.81l134.25 4.24-33.9 80.92z"/><path fill="#e09b16" d="m350.77 301.33l43.78 28.12 43.56-67.74-104-25.5z"/><path fill="#cb4f83" d="m410.4 304.77l-15.03 25.52-44.6-28.96-11.33-42.89 49.11 27.8z"/><path fill="#c7e4f1" d="m318.46 247.61l150.29-116.2-80.2 154.83z"/><path fill="#af2527" d="m396.71 322.99l-77.18-16.89 31.24-4.77z"/></g></g><use opacity=".8" fill="#1e5a6e" xlink:href="#2"/><g fill="none" stroke="#fff" stroke-width="2" stroke-miterlimit="10"><path d="m355 284.82h40"/><path d="m355 294.82h40"/></g></svg>
|
After Width: | Height: | Size: 3.5 KiB |
1
public/assets/error/error-3.svg
Normal file
1
public/assets/error/error-3.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.4 KiB |
1
public/assets/error/error-4.svg
Normal file
1
public/assets/error/error-4.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 19 KiB |
BIN
public/assets/error/firasans-regular-webfont.eot
Executable file
BIN
public/assets/error/firasans-regular-webfont.eot
Executable file
Binary file not shown.
BIN
public/assets/error/firasans-regular-webfont.ttf
Executable file
BIN
public/assets/error/firasans-regular-webfont.ttf
Executable file
Binary file not shown.
BIN
public/assets/error/firasans-regular-webfont.woff
Executable file
BIN
public/assets/error/firasans-regular-webfont.woff
Executable file
Binary file not shown.
80
public/assets/error/style.css
Normal file
80
public/assets/error/style.css
Normal file
|
@ -0,0 +1,80 @@
|
|||
@font-face {
|
||||
font-family: 'Fira Sans';
|
||||
src: url('firasans-regular-webfont.eot');
|
||||
src: url('firasans-regular-webfont.eot?#iefix') format('embedded-opentype'),
|
||||
url('firasans-regular-webfont.woff') format('woff'),
|
||||
url('firasans-regular-webfont.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: "Fira Sans";
|
||||
height: 100%;
|
||||
color: #8c959c;
|
||||
background: #f8f9fa;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dark {
|
||||
background: #444a4f;
|
||||
color: #919497;
|
||||
}
|
||||
|
||||
body {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
min-height: 600px;
|
||||
margin: 0;
|
||||
padding: 40px 10px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
color: #444a4f;
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
.dark h1 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #f1d158;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:visited {
|
||||
color: #ccb250;
|
||||
}
|
||||
|
||||
ul {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 400px;
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
|
||||
.error-image {
|
||||
height: 650px;
|
||||
width: 100%;
|
||||
margin: 30px 0;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
|
@ -44,7 +44,7 @@ test( "model ui basic tests", function() {
|
|||
equal( App.viewPrint( ticket, 'state' ), 'open')
|
||||
equal( App.viewPrint( ticket, 'state_id' ), 'open')
|
||||
equal( App.viewPrint( ticket, 'not_existing' ), '-')
|
||||
equal( App.viewPrint( ticket, 'updated_at' ), "<span class=\"humanTimeFromNow undefined\" data-time=\"2014-11-07T23:43:08.000Z\">?</span>")
|
||||
equal( App.viewPrint( ticket, 'updated_at' ), '<time class="humanTimeFromNow " data-time="2014-11-07T23:43:08.000Z" data-tooltip="11/07/2014 23:43">11/07/2014</time>')
|
||||
equal( App.viewPrint( ticket, 'date' ), '02/07/2015')
|
||||
equal( App.viewPrint( ticket, 'textarea' ), '<div>some new</div><div>line</div>')
|
||||
|
||||
|
@ -55,7 +55,7 @@ test( "model ui basic tests", function() {
|
|||
equal( App.viewPrint( ticket, 'state' ), 'offen')
|
||||
equal( App.viewPrint( ticket, 'state_id' ), 'offen')
|
||||
equal( App.viewPrint( ticket, 'not_existing' ), '-')
|
||||
equal( App.viewPrint( ticket, 'updated_at' ), "<span class=\"humanTimeFromNow undefined\" data-time=\"2014-11-07T23:43:08.000Z\">?</span>")
|
||||
equal( App.viewPrint( ticket, 'updated_at' ), '<time class="humanTimeFromNow " data-time="2014-11-07T23:43:08.000Z" data-tooltip="07.11.2014 23:43">07.11.2014</time>')
|
||||
equal( App.viewPrint( ticket, 'date' ), '07.02.2015')
|
||||
equal( App.viewPrint( ticket, 'textarea' ), '<div>some new</div><div>line</div>')
|
||||
|
||||
|
|
|
@ -91,11 +91,11 @@ test( "table test", function() {
|
|||
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '?', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '?', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2')
|
||||
|
||||
$('#table').append('<hr><h1>table simple II</h1><div id="table2"></div>')
|
||||
|
@ -114,11 +114,11 @@ test( "table test", function() {
|
|||
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '2 normal', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '?', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'false', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '1 niedrig', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '?', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', 'check row 2')
|
||||
|
||||
$('#table').append('<hr><h1>table simple III</h1><div id="table3"></div>')
|
||||
|
@ -257,7 +257,7 @@ test( "table test", function() {
|
|||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(6)').text().trim(), '2 normal', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(7)').text().trim(), 'group 2', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(8)').text().trim(), 'neu', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(9)').text().trim(), '?', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(9)').text().trim(), '11.07.2014', 'check row 1')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td').length, 9, 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2')
|
||||
|
@ -269,7 +269,7 @@ test( "table test", function() {
|
|||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'group 1', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), 'offen', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(9)').text().trim(), '?', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td').length, 9, 'check row 3')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), '', 'check row 3')
|
||||
|
@ -281,7 +281,7 @@ test( "table test", function() {
|
|||
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 3')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(7)').text().trim(), 'group 2', 'check row 3')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(8)').text().trim(), 'neu', 'check row 3')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(9)').text().trim(), '?', 'check row 3')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 3')
|
||||
|
||||
el.find('input[name="bulk_all"]').click()
|
||||
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), true, 'check row 1')
|
||||
|
@ -330,7 +330,7 @@ test( "table test", function() {
|
|||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'offen', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), '?', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), '10.06.2014', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td').length, 1, 'check row 3')
|
||||
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), 'group 2', 'check row 4')
|
||||
equal( el.find('tbody > tr:nth-child(4) > td').length, 8, 'check row 4')
|
||||
|
@ -343,7 +343,7 @@ test( "table test", function() {
|
|||
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(5)').text().trim(), '-', 'check row 2')
|
||||
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(6)').text().trim(), '2 normal', 'check row 4')
|
||||
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(7)').text().trim(), 'neu', 'check row 4')
|
||||
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(8)').text().trim(), '?', 'check row 4')
|
||||
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(8)').text().trim(), '11.07.2014', 'check row 4')
|
||||
|
||||
el.find('input[name="bulk"]:eq(1)').click()
|
||||
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2')
|
||||
|
|
|
@ -12,6 +12,12 @@ require 'sessions'
|
|||
require 'optparse'
|
||||
require 'daemons'
|
||||
|
||||
# load rails env
|
||||
dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
||||
Dir.chdir dir
|
||||
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
|
||||
require File.join(dir, 'config', 'environment')
|
||||
|
||||
# Look for -o with argument, and -I and -D boolean arguments
|
||||
@options = {
|
||||
p: 6042,
|
||||
|
@ -176,10 +182,23 @@ EventMachine.run {
|
|||
|
||||
# get session
|
||||
if data['action'] == 'login'
|
||||
@clients[client_id][:session] = data['session']
|
||||
Sessions.create( client_id, data['session'], { type: 'websocket' } )
|
||||
|
||||
# remember ping, send pong back
|
||||
# get user_id
|
||||
if data && data['session_id']
|
||||
session = ActiveRecord::SessionStore::Session.find_by( session_id: data['session_id'] )
|
||||
end
|
||||
|
||||
if session && session.data && session.data['user_id']
|
||||
new_session_data = { 'id' => session.data['user_id'] }
|
||||
else
|
||||
new_session_data = {}
|
||||
end
|
||||
|
||||
@clients[client_id][:session] = new_session_data
|
||||
|
||||
Sessions.create( client_id, new_session_data, { type: 'websocket' } )
|
||||
|
||||
# remember ping, send pong back
|
||||
elsif data['action'] == 'ping'
|
||||
Sessions.touch(client_id)
|
||||
@clients[client_id][:last_ping] = Time.now.utc.to_i
|
||||
|
@ -188,7 +207,7 @@ EventMachine.run {
|
|||
}
|
||||
websocket_send(client_id, message)
|
||||
|
||||
# broadcast
|
||||
# broadcast
|
||||
elsif data['action'] == 'broadcast'
|
||||
|
||||
# list all current clients
|
||||
|
|
103
test/controllers/packages_controller_test.rb
Normal file
103
test/controllers/packages_controller_test.rb
Normal file
|
@ -0,0 +1,103 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class PackagesControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
|
||||
# set accept header
|
||||
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: %w(Admin Agent) )
|
||||
groups = Group.all
|
||||
|
||||
UserInfo.current_user_id = 1
|
||||
@admin = User.create_or_update(
|
||||
login: 'packages-admin',
|
||||
firstname: 'Packages',
|
||||
lastname: 'Admin',
|
||||
email: 'packages-admin@example.com',
|
||||
password: 'adminpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: 'Agent' )
|
||||
@agent = User.create_or_update(
|
||||
login: 'packages-agent@example.com',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Agent',
|
||||
email: 'packages-agent@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create customer without org
|
||||
roles = Role.where( name: 'Customer' )
|
||||
@customer_without_org = User.create_or_update(
|
||||
login: 'packages-customer1@example.com',
|
||||
firstname: 'Packages',
|
||||
lastname: 'Customer1',
|
||||
email: 'packages-customer1@example.com',
|
||||
password: 'customer1pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
test 'packages index with nobody' do
|
||||
|
||||
# index
|
||||
get '/api/v1/packages'
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result['packages'])
|
||||
|
||||
end
|
||||
|
||||
test 'packages index with admin' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-admin@example.com', 'adminpw')
|
||||
|
||||
# index
|
||||
get '/api/v1/packages', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert(result['packages'])
|
||||
|
||||
end
|
||||
|
||||
test 'packages index with agent' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-agent@example.com', 'adminpw')
|
||||
|
||||
# index
|
||||
get '/api/v1/packages', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result['packages'])
|
||||
|
||||
end
|
||||
|
||||
test 'packages index with customer' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-customer1@example.com', 'customer1pw')
|
||||
|
||||
# index
|
||||
get '/api/v1/packages', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result['packages'])
|
||||
|
||||
end
|
||||
|
||||
end
|
456
test/controllers/search_controller_test.rb
Normal file
456
test/controllers/search_controller_test.rb
Normal file
|
@ -0,0 +1,456 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class SearchControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
|
||||
# set accept header
|
||||
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: %w(Admin Agent) )
|
||||
groups = Group.all
|
||||
|
||||
UserInfo.current_user_id = 1
|
||||
@admin = User.create_or_update(
|
||||
login: 'search-admin',
|
||||
firstname: 'Search',
|
||||
lastname: 'Admin',
|
||||
email: 'search-admin@example.com',
|
||||
password: 'adminpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: 'Agent' )
|
||||
@agent = User.create_or_update(
|
||||
login: 'search-agent@example.com',
|
||||
firstname: 'Search 1234',
|
||||
lastname: 'Agent',
|
||||
email: 'search-agent@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create customer without org
|
||||
roles = Role.where( name: 'Customer' )
|
||||
@customer_without_org = User.create_or_update(
|
||||
login: 'search-customer1@example.com',
|
||||
firstname: 'Search',
|
||||
lastname: 'Customer1',
|
||||
email: 'search-customer1@example.com',
|
||||
password: 'customer1pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
)
|
||||
|
||||
# create orgs
|
||||
@organization = Organization.create_or_update(
|
||||
name: 'Rest Org',
|
||||
)
|
||||
@organization2 = Organization.create_or_update(
|
||||
name: 'Rest Org #2',
|
||||
)
|
||||
@organization3 = Organization.create_or_update(
|
||||
name: 'Rest Org #3',
|
||||
)
|
||||
|
||||
# create customer with org
|
||||
@customer_with_org2 = User.create_or_update(
|
||||
login: 'search-customer2@example.com',
|
||||
firstname: 'Search',
|
||||
lastname: 'Customer2',
|
||||
email: 'search-customer2@example.com',
|
||||
password: 'customer2pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
organization_id: @organization.id,
|
||||
)
|
||||
|
||||
@customer_with_org3 = User.create_or_update(
|
||||
login: 'search-customer3@example.com',
|
||||
firstname: 'Search',
|
||||
lastname: 'Customer3',
|
||||
email: 'search-customer3@example.com',
|
||||
password: 'customer3pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
organization_id: @organization.id,
|
||||
)
|
||||
|
||||
Ticket.all.destroy_all
|
||||
|
||||
@ticket1 = Ticket.create(
|
||||
title: 'test 1234-1',
|
||||
group: Group.lookup( name: 'Users'),
|
||||
customer_id: @customer_without_org.id,
|
||||
state: Ticket::State.lookup( name: 'new' ),
|
||||
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
@article1 = Ticket::Article.create(
|
||||
ticket_id: @ticket1.id,
|
||||
from: 'some_sender1@example.com',
|
||||
to: 'some_recipient1@example.com',
|
||||
subject: 'some subject1',
|
||||
message_id: 'some@id',
|
||||
body: 'some message1',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
@ticket2 = Ticket.create(
|
||||
title: 'test 1234-2',
|
||||
group: Group.lookup( name: 'Users'),
|
||||
customer_id: @customer_with_org2.id,
|
||||
state: Ticket::State.lookup( name: 'new' ),
|
||||
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
@article2 = Ticket::Article.create(
|
||||
ticket_id: @ticket2.id,
|
||||
from: 'some_sender2@example.com',
|
||||
to: 'some_recipient2@example.com',
|
||||
subject: 'some subject2',
|
||||
message_id: 'some@id',
|
||||
body: 'some message2',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
@ticket3 = Ticket.create(
|
||||
title: 'test 1234-2',
|
||||
group: Group.lookup( name: 'Users'),
|
||||
customer_id: @customer_with_org3.id,
|
||||
state: Ticket::State.lookup( name: 'new' ),
|
||||
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
@article3 = Ticket::Article.create(
|
||||
ticket_id: @ticket3.id,
|
||||
from: 'some_sender3@example.com',
|
||||
to: 'some_recipient3@example.com',
|
||||
subject: 'some subject3',
|
||||
message_id: 'some@id',
|
||||
body: 'some message3',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
# configure es
|
||||
if ENV['ES_URL']
|
||||
#fail "ERROR: Need ES_URL - hint ES_URL='http://172.0.0.1:9200'"
|
||||
Setting.set('es_url', ENV['ES_URL'])
|
||||
|
||||
# Setting.set('es_url', 'http://172.0.0.1:9200')
|
||||
# Setting.set('es_index', 'estest.local_zammad')
|
||||
# Setting.set('es_user', 'elasticsearch')
|
||||
# Setting.set('es_password', 'zammad')
|
||||
|
||||
# set max attachment size in mb
|
||||
Setting.set('es_attachment_max_size_in_mb', 1 )
|
||||
|
||||
if ENV['ES_INDEX']
|
||||
#fail "ERROR: Need ES_INDEX - hint ES_INDEX='estest.local_zammad'"
|
||||
Setting.set('es_index', ENV['ES_INDEX'])
|
||||
end
|
||||
|
||||
# drop/create indexes
|
||||
#Rake::Task["searchindex:drop"].execute
|
||||
#Rake::Task["searchindex:create"].execute
|
||||
system('rake searchindex:rebuild')
|
||||
|
||||
# execute background jobs
|
||||
# execute background jobs
|
||||
#puts Delayed::Job.all.inspect
|
||||
Delayed::Worker.new.work_off
|
||||
|
||||
sleep 6
|
||||
end
|
||||
end
|
||||
|
||||
test 'settings index with nobody' do
|
||||
|
||||
params = {
|
||||
query: 'test 1234',
|
||||
limit: 2,
|
||||
}
|
||||
|
||||
post '/api/v1/search/ticket', params.to_json, @headers
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result.empty?)
|
||||
|
||||
post '/api/v1/search/user', params.to_json, @headers
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result.empty?)
|
||||
|
||||
post '/api/v1/search', params.to_json, @headers
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result.empty?)
|
||||
|
||||
end
|
||||
|
||||
test 'settings index with admin' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('search-admin@example.com', 'adminpw')
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 1,
|
||||
}
|
||||
|
||||
post '/api/v1/search', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket3.id, result['result'][0]['id'])
|
||||
assert_equal('User', result['result'][1]['type'])
|
||||
assert_equal(@agent.id, result['result'][1]['id'])
|
||||
assert_not(result['result'][2])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket3.id, result['result'][0]['id'])
|
||||
assert_equal('Ticket', result['result'][1]['type'])
|
||||
assert_equal(@ticket2.id, result['result'][1]['id'])
|
||||
assert_equal('Ticket', result['result'][2]['type'])
|
||||
assert_equal(@ticket1.id, result['result'][2]['id'])
|
||||
assert_equal('User', result['result'][3]['type'])
|
||||
assert_equal(@agent.id, result['result'][3]['id'])
|
||||
assert_not(result['result'][4])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search/ticket', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket3.id, result['result'][0]['id'])
|
||||
assert_equal('Ticket', result['result'][1]['type'])
|
||||
assert_equal(@ticket2.id, result['result'][1]['id'])
|
||||
assert_equal('Ticket', result['result'][2]['type'])
|
||||
assert_equal(@ticket1.id, result['result'][2]['id'])
|
||||
assert_not(result['result'][3])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search/user', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_equal('User', result['result'][0]['type'])
|
||||
assert_equal(@agent.id, result['result'][0]['id'])
|
||||
assert_not(result['result'][1])
|
||||
|
||||
end
|
||||
|
||||
test 'settings index with agent' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('search-agent@example.com', 'agentpw')
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 1,
|
||||
}
|
||||
|
||||
post '/api/v1/search', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket3.id, result['result'][0]['id'])
|
||||
assert_equal('User', result['result'][1]['type'])
|
||||
assert_equal(@agent.id, result['result'][1]['id'])
|
||||
assert_not(result['result'][2])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket3.id, result['result'][0]['id'])
|
||||
assert_equal('Ticket', result['result'][1]['type'])
|
||||
assert_equal(@ticket2.id, result['result'][1]['id'])
|
||||
assert_equal('Ticket', result['result'][2]['type'])
|
||||
assert_equal(@ticket1.id, result['result'][2]['id'])
|
||||
assert_equal('User', result['result'][3]['type'])
|
||||
assert_equal(@agent.id, result['result'][3]['id'])
|
||||
assert_not(result['result'][4])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search/ticket', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket3.id, result['result'][0]['id'])
|
||||
assert_equal('Ticket', result['result'][1]['type'])
|
||||
assert_equal(@ticket2.id, result['result'][1]['id'])
|
||||
assert_equal('Ticket', result['result'][2]['type'])
|
||||
assert_equal(@ticket1.id, result['result'][2]['id'])
|
||||
assert_not(result['result'][3])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search/user', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_equal('User', result['result'][0]['type'])
|
||||
assert_equal(@agent.id, result['result'][0]['id'])
|
||||
assert_not(result['result'][1])
|
||||
|
||||
end
|
||||
|
||||
test 'settings index with customer 1' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('search-customer1@example.com', 'customer1pw')
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket1.id, result['result'][0]['id'])
|
||||
assert_not(result['result'][1])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search/ticket', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket1.id, result['result'][0]['id'])
|
||||
assert_not(result['result'][1])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search/user', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_not(result['result'][0])
|
||||
|
||||
end
|
||||
|
||||
test 'settings index with customer 2' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('search-customer2@example.com', 'customer2pw')
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket3.id, result['result'][0]['id'])
|
||||
assert_equal('Ticket', result['result'][1]['type'])
|
||||
assert_equal(@ticket2.id, result['result'][1]['id'])
|
||||
assert_not(result['result'][2])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search/ticket', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert(result)
|
||||
assert_equal('Ticket', result['result'][0]['type'])
|
||||
assert_equal(@ticket3.id, result['result'][0]['id'])
|
||||
assert_equal('Ticket', result['result'][1]['type'])
|
||||
assert_equal(@ticket2.id, result['result'][1]['id'])
|
||||
assert_not(result['result'][2])
|
||||
|
||||
params = {
|
||||
query: '1234*',
|
||||
limit: 10,
|
||||
}
|
||||
|
||||
post '/api/v1/search/user', params.to_json, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_not(result['result'][0])
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
103
test/controllers/settings_controller_test.rb
Normal file
103
test/controllers/settings_controller_test.rb
Normal file
|
@ -0,0 +1,103 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class SettingsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
|
||||
# set accept header
|
||||
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: %w(Admin Agent) )
|
||||
groups = Group.all
|
||||
|
||||
UserInfo.current_user_id = 1
|
||||
@admin = User.create_or_update(
|
||||
login: 'packages-admin',
|
||||
firstname: 'Packages',
|
||||
lastname: 'Admin',
|
||||
email: 'packages-admin@example.com',
|
||||
password: 'adminpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: 'Agent' )
|
||||
@agent = User.create_or_update(
|
||||
login: 'packages-agent@example.com',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Agent',
|
||||
email: 'packages-agent@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create customer without org
|
||||
roles = Role.where( name: 'Customer' )
|
||||
@customer_without_org = User.create_or_update(
|
||||
login: 'packages-customer1@example.com',
|
||||
firstname: 'Packages',
|
||||
lastname: 'Customer1',
|
||||
email: 'packages-customer1@example.com',
|
||||
password: 'customer1pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
test 'settings index with nobody' do
|
||||
|
||||
# index
|
||||
get '/api/v1/settings'
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result['settings'])
|
||||
|
||||
end
|
||||
|
||||
test 'settings index with admin' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-admin@example.com', 'adminpw')
|
||||
|
||||
# index
|
||||
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Array, result.class)
|
||||
assert(result)
|
||||
|
||||
end
|
||||
|
||||
test 'settings index with agent' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-agent@example.com', 'adminpw')
|
||||
|
||||
# index
|
||||
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result['settings'])
|
||||
|
||||
end
|
||||
|
||||
test 'settings index with customer' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('packages-customer1@example.com', 'customer1pw')
|
||||
|
||||
# index
|
||||
get '/api/v1/settings', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_not(result['settings'])
|
||||
|
||||
end
|
||||
|
||||
end
|
325
test/controllers/user_organization_controller_test.rb
Normal file
325
test/controllers/user_organization_controller_test.rb
Normal file
|
@ -0,0 +1,325 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
|
||||
# set accept header
|
||||
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: %w(Admin Agent) )
|
||||
groups = Group.all
|
||||
|
||||
UserInfo.current_user_id = 1
|
||||
@admin = User.create_or_update(
|
||||
login: 'rest-admin',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Agent',
|
||||
email: 'rest-admin@example.com',
|
||||
password: 'adminpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: 'Agent' )
|
||||
@agent = User.create_or_update(
|
||||
login: 'rest-agent@example.com',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Agent',
|
||||
email: 'rest-agent@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create customer without org
|
||||
roles = Role.where( name: 'Customer' )
|
||||
@customer_without_org = User.create_or_update(
|
||||
login: 'rest-customer1@example.com',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Customer1',
|
||||
email: 'rest-customer1@example.com',
|
||||
password: 'customer1pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
)
|
||||
|
||||
# create orgs
|
||||
@organization = Organization.create_or_update(
|
||||
name: 'Rest Org',
|
||||
)
|
||||
@organization2 = Organization.create_or_update(
|
||||
name: 'Rest Org #2',
|
||||
)
|
||||
@organization3 = Organization.create_or_update(
|
||||
name: 'Rest Org #3',
|
||||
)
|
||||
|
||||
# create customer with org
|
||||
@customer_with_org = User.create_or_update(
|
||||
login: 'rest-customer2@example.com',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Customer2',
|
||||
email: 'rest-customer2@example.com',
|
||||
password: 'customer2pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
organization_id: @organization.id,
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
test 'user create tests - no user' do
|
||||
|
||||
# create user with disabled feature
|
||||
Setting.set('user_create_account', false)
|
||||
post '/api/v1/users', {}, @headers
|
||||
assert_response(422)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result['error'])
|
||||
assert_equal('Feature not enabled!', result['error'])
|
||||
|
||||
# already existing user with enabled feature
|
||||
Setting.set('user_create_account', true)
|
||||
params = { email: 'rest-customer1@example.com' }
|
||||
post '/api/v1/users', params.to_json, @headers
|
||||
assert_response(422)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result['error'])
|
||||
assert_equal('User already exists!', result['error'])
|
||||
|
||||
# create user with enabled feature
|
||||
params = { firstname: 'Me First', lastname: 'Me Last', email: 'new_here@example.com' }
|
||||
post '/api/v1/users', params.to_json, @headers
|
||||
assert_response(201)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result)
|
||||
|
||||
assert_equal('Me First', result['firstname'])
|
||||
assert_equal('Me Last', result['lastname'])
|
||||
assert_equal('new_here@example.com', result['login'])
|
||||
assert_equal('new_here@example.com', result['email'])
|
||||
|
||||
# no user
|
||||
get '/api/v1/users', {}, @headers
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal('authentication failed', result['error'])
|
||||
end
|
||||
|
||||
test 'auth tests - not existing user' do
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('not_existing@example.com', 'adminpw')
|
||||
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal('authentication failed', result['error'])
|
||||
end
|
||||
|
||||
test 'auth tests - username auth, wrong pw' do
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin', 'not_existing')
|
||||
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal('authentication failed', result['error'])
|
||||
end
|
||||
|
||||
test 'auth tests - email auth, wrong pw' do
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'not_existing')
|
||||
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal('authentication failed', result['error'])
|
||||
end
|
||||
|
||||
test 'auth tests - username auth' do
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin', 'adminpw')
|
||||
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result)
|
||||
end
|
||||
|
||||
test 'auth tests - email auth' do
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
|
||||
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result)
|
||||
end
|
||||
|
||||
test 'user index with admin' do
|
||||
|
||||
# email auth
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
|
||||
|
||||
# index
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result)
|
||||
|
||||
# index
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result)
|
||||
assert_equal(result.class, Array)
|
||||
assert(result.length >= 3)
|
||||
|
||||
# show/:id
|
||||
get "/api/v1/users/#{@agent.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_equal(result['email'], 'rest-agent@example.com')
|
||||
|
||||
get "/api/v1/users/#{@customer_without_org.id}", {}, 'Authorization' => credentials
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert(result)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_equal(result['email'], 'rest-customer1@example.com')
|
||||
|
||||
end
|
||||
|
||||
test 'user index with customer1' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-customer1@example.com', 'customer1pw')
|
||||
|
||||
# index
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Array)
|
||||
assert_equal(result.length, 1)
|
||||
|
||||
# show/:id
|
||||
get "/api/v1/users/#{@customer_without_org.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_equal(result['email'], 'rest-customer1@example.com')
|
||||
|
||||
get "/api/v1/users/#{@customer_with_org.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert(result.empty?)
|
||||
|
||||
end
|
||||
|
||||
test 'user index with customer2' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-customer2@example.com', 'customer2pw')
|
||||
|
||||
# index
|
||||
get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Array)
|
||||
assert_equal(result.length, 1)
|
||||
|
||||
# show/:id
|
||||
get "/api/v1/users/#{@customer_with_org.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert_equal(result['email'], 'rest-customer2@example.com')
|
||||
|
||||
get "/api/v1/users/#{@customer_without_org.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
#puts @response.body
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Hash)
|
||||
assert(result.empty?)
|
||||
|
||||
end
|
||||
|
||||
test 'organization index with agent' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-agent@example.com', 'agentpw')
|
||||
|
||||
# index
|
||||
get '/api/v1/organizations', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Array)
|
||||
assert(result.length >= 3)
|
||||
|
||||
# show/:id
|
||||
get "/api/v1/organizations/#{@organization.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal( result.class, Hash)
|
||||
assert_equal( result['name'], 'Rest Org')
|
||||
|
||||
get "/api/v1/organizations/#{@organization2.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal( result.class, Hash)
|
||||
assert_equal( result['name'], 'Rest Org #2')
|
||||
|
||||
end
|
||||
|
||||
test 'organization index with customer1' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-customer1@example.com', 'customer1pw')
|
||||
|
||||
# index
|
||||
get '/api/v1/organizations', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Array)
|
||||
assert_equal(result.length, 0)
|
||||
|
||||
# show/:id
|
||||
get "/api/v1/organizations/#{@organization.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal( result.class, Hash)
|
||||
assert_equal( result['name'], nil)
|
||||
|
||||
get "/api/v1/organizations/#{@organization2.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal( result.class, Hash)
|
||||
assert_equal( result['name'], nil)
|
||||
|
||||
end
|
||||
|
||||
test 'organization index with customer2' do
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-customer2@example.com', 'customer2pw')
|
||||
|
||||
# index
|
||||
get '/api/v1/organizations', {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(result.class, Array)
|
||||
assert_equal(result.length, 1)
|
||||
|
||||
# show/:id
|
||||
get "/api/v1/organizations/#{@organization.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(200)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal( result.class, Hash)
|
||||
assert_equal( result['name'], 'Rest Org')
|
||||
|
||||
get "/api/v1/organizations/#{@organization2.id}", {}, @headers.merge('Authorization' => credentials)
|
||||
assert_response(401)
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal( result.class, Hash)
|
||||
assert_equal( result['name'], nil)
|
||||
|
||||
end
|
||||
end
|
|
@ -235,4 +235,13 @@ class ModelTest < ActiveSupport::TestCase
|
|||
|
||||
end
|
||||
|
||||
test 'searchable test' do
|
||||
searchable = Models.searchable
|
||||
assert(searchable.include?(Ticket))
|
||||
assert(searchable.include?(User))
|
||||
assert(searchable.include?(Organization))
|
||||
assert_equal(3, searchable.count)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,244 +0,0 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class RestTest < ActiveSupport::TestCase
|
||||
|
||||
test 'users and orgs' do
|
||||
|
||||
if !ENV['BROWSER_URL']
|
||||
puts 'NOTICE: Do not execute rest tests, no BROWSER_URL=http://some_host:port is defined! e. g. export BROWSER_URL=http://localhost:3000'
|
||||
return
|
||||
end
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: %w(Admin Agent) )
|
||||
groups = Group.all
|
||||
|
||||
UserInfo.current_user_id = 1
|
||||
admin = User.create_or_update(
|
||||
login: 'rest-admin',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Agent',
|
||||
email: 'rest-admin@example.com',
|
||||
password: 'adminpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create agent
|
||||
roles = Role.where( name: 'Agent' )
|
||||
agent = User.create_or_update(
|
||||
login: 'rest-agent@example.com',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Agent',
|
||||
email: 'rest-agent@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
|
||||
# create customer without org
|
||||
roles = Role.where( name: 'Customer' )
|
||||
customer_without_org = User.create_or_update(
|
||||
login: 'rest-customer1@example.com',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Customer1',
|
||||
email: 'rest-customer1@example.com',
|
||||
password: 'customer1pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
)
|
||||
|
||||
# create orgs
|
||||
organization = Organization.create_or_update(
|
||||
name: 'Rest Org',
|
||||
)
|
||||
organization2 = Organization.create_or_update(
|
||||
name: 'Rest Org #2',
|
||||
)
|
||||
organization3 = Organization.create_or_update(
|
||||
name: 'Rest Org #3',
|
||||
)
|
||||
|
||||
# create customer with org
|
||||
customer_with_org = User.create_or_update(
|
||||
login: 'rest-customer2@example.com',
|
||||
firstname: 'Rest',
|
||||
lastname: 'Customer2',
|
||||
email: 'rest-customer2@example.com',
|
||||
password: 'customer2pw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
organization_id: organization.id,
|
||||
)
|
||||
|
||||
# not existing user
|
||||
request = get( 'not_existing@example.com', 'adminpw', '/api/v1/users')
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
# username auth, wrong pw
|
||||
request = get( 'rest-admin', 'not_existing', '/api/v1/users' )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
# email auth, wrong pw
|
||||
request = get( 'rest-admin@example.com', 'not_existing', '/api/v1/users' )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
# username auth
|
||||
request = get( 'rest-admin', 'adminpw', '/api/v1/users' )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
|
||||
# email auth
|
||||
request = get( 'rest-admin@example.com', 'adminpw', '/api/v1/users' )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
|
||||
# /users
|
||||
|
||||
# index
|
||||
request = get( 'rest-agent@example.com', 'agentpw', '/api/v1/users')
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
assert( request[:data].length >= 3 )
|
||||
|
||||
# show/:id
|
||||
request = get( 'rest-agent@example.com', 'agentpw', '/api/v1/users/' + agent.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['email'], 'rest-agent@example.com')
|
||||
request = get( 'rest-agent@example.com', 'agentpw', '/api/v1/users/' + customer_without_org.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['email'], 'rest-customer1@example.com')
|
||||
|
||||
# index
|
||||
request = get( 'rest-customer1@example.com', 'customer1pw', '/api/v1/users')
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
assert_equal( request[:data].length, 1 )
|
||||
|
||||
# show/:id
|
||||
request = get( 'rest-customer1@example.com', 'customer1pw', '/api/v1/users/' + customer_without_org.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['email'], 'rest-customer1@example.com')
|
||||
request = get( 'rest-customer1@example.com', 'customer1pw', '/api/v1/users/' + customer_with_org.id.to_s )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
# index
|
||||
request = get( 'rest-customer2@example.com', 'customer2pw', '/api/v1/users')
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
assert_equal( request[:data].length, 1 )
|
||||
|
||||
# show/:id
|
||||
request = get( 'rest-customer2@example.com', 'customer2pw', '/api/v1/users/' + customer_with_org.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['email'], 'rest-customer2@example.com')
|
||||
request = get( 'rest-customer2@example.com', 'customer2pw', '/api/v1/users/' + customer_without_org.id.to_s )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
# /organizations
|
||||
|
||||
# index
|
||||
request = get( 'rest-agent@example.com', 'agentpw', '/api/v1/organizations')
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
assert( request[:data].length >= 3 )
|
||||
|
||||
# show/:id
|
||||
request = get( 'rest-agent@example.com', 'agentpw', '/api/v1/organizations/' + organization.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['name'], 'Rest Org')
|
||||
request = get( 'rest-agent@example.com', 'agentpw', '/api/v1/organizations/' + organization2.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['name'], 'Rest Org #2')
|
||||
|
||||
# index
|
||||
request = get( 'rest-customer1@example.com', 'customer1pw', '/api/v1/organizations')
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
assert_equal( request[:data].length, 0 )
|
||||
|
||||
# show/:id
|
||||
request = get( 'rest-customer1@example.com', 'customer1pw', '/api/v1/organizations/' + organization.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['name'], nil)
|
||||
request = get( 'rest-customer1@example.com', 'customer1pw', '/api/v1/organizations/' + organization2.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['name'], nil)
|
||||
|
||||
# index
|
||||
request = get( 'rest-customer2@example.com', 'customer2pw', '/api/v1/organizations')
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
assert_equal( request[:data].length, 1 )
|
||||
|
||||
# show/:id
|
||||
request = get( 'rest-customer2@example.com', 'customer2pw', '/api/v1/organizations/' + organization.id.to_s )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert_equal( request[:data]['name'], 'Rest Org')
|
||||
request = get( 'rest-customer2@example.com', 'customer2pw', '/api/v1/organizations/' + organization2.id.to_s )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
# packages
|
||||
request = get( 'rest-admin@example.com', 'adminpw', '/api/v1/packages' )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Hash)
|
||||
assert( request[:data]['packages'] )
|
||||
|
||||
request = get( 'rest-agent@example.com', 'agentpw', '/api/v1/packages' )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
request = get( 'rest-customer1@example.com', 'customer1pw', '/api/v1/packages' )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
# settings
|
||||
request = get( 'rest-admin@example.com', 'adminpw', '/api/v1/settings' )
|
||||
assert_equal( request[:response].code, '200' )
|
||||
assert_equal( request[:data].class, Array)
|
||||
assert( request[:data][0] )
|
||||
|
||||
request = get( 'rest-agent@example.com', 'agentpw', '/api/v1/settings' )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
request = get( 'rest-customer1@example.com', 'customer1pw', '/api/v1/settings' )
|
||||
assert_equal( request[:response].code, '401' )
|
||||
assert_equal( request[:data].class, NilClass)
|
||||
|
||||
end
|
||||
def get(user, pw, url)
|
||||
|
||||
response = UserAgent.get(
|
||||
"#{ENV['BROWSER_URL']}#{url}",
|
||||
{},
|
||||
{
|
||||
json: true,
|
||||
user: user,
|
||||
password: pw,
|
||||
}
|
||||
)
|
||||
#puts 'URL: ' + url
|
||||
#puts response.code.to_s
|
||||
#puts response.body.to_s
|
||||
{ data: response.data, response: response }
|
||||
end
|
||||
end
|
190
test/unit/user_device_test.rb
Normal file
190
test/unit/user_device_test.rb
Normal file
|
@ -0,0 +1,190 @@
|
|||
require 'test_helper'
|
||||
|
||||
class UserDeviceTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
|
||||
# create agent
|
||||
groups = Group.all
|
||||
roles = Role.where( name: 'Agent' )
|
||||
|
||||
UserInfo.current_user_id = 1
|
||||
|
||||
@agent = User.create_or_update(
|
||||
login: 'user-device-agent@example.com',
|
||||
firstname: 'UserDevice',
|
||||
lastname: 'Agent',
|
||||
email: 'user-device-agent@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
test 'session test' do
|
||||
|
||||
# signin with fingerprint A from country A via session -> new device #1
|
||||
user_device1 = 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',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
'fingerprint1234',
|
||||
'session',
|
||||
)
|
||||
|
||||
# signin with fingerprint A from country B via session -> new device #2
|
||||
user_device2 = 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',
|
||||
'176.198.137.254',
|
||||
@agent.id,
|
||||
'fingerprint1234',
|
||||
'session',
|
||||
)
|
||||
assert_not_equal(user_device1.id, user_device2.id)
|
||||
|
||||
# signin with fingerprint B from country A via session -> new device #3
|
||||
user_device3 = 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',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
'fingerprintABC',
|
||||
'session',
|
||||
)
|
||||
assert_not_equal(user_device2.id, user_device3.id)
|
||||
|
||||
# signin with fingerprint A from country A via session -> new device #1
|
||||
user_device4 = 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',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
'fingerprint1234',
|
||||
'session',
|
||||
)
|
||||
assert_equal(user_device1.id, user_device4.id)
|
||||
|
||||
# signin with fingerprint A from country B via session -> new device #2
|
||||
user_device5 = 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',
|
||||
'176.198.137.254',
|
||||
@agent.id,
|
||||
'fingerprint1234',
|
||||
'session',
|
||||
)
|
||||
assert_equal(user_device2.id, user_device5.id)
|
||||
|
||||
# signin with fingerprint B from country A via session -> new device #3
|
||||
user_device6 = 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',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
'fingerprintABC',
|
||||
'session',
|
||||
)
|
||||
assert_equal(user_device3.id, user_device6.id)
|
||||
|
||||
end
|
||||
|
||||
test 'session test - user agent (unknown)' do
|
||||
|
||||
# known user agent
|
||||
user_device1 = 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',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
nil,
|
||||
'session',
|
||||
)
|
||||
assert_equal('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', user_device1.user_agent)
|
||||
assert_equal('Mac, Chrome', user_device1.name)
|
||||
|
||||
# unknown user agent
|
||||
user_device2 = UserDevice.add(
|
||||
'ABC 123',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
nil,
|
||||
'session',
|
||||
)
|
||||
assert_equal('ABC 123', user_device2.user_agent)
|
||||
assert_equal('ABC 123', user_device2.browser)
|
||||
assert_equal('ABC 123', user_device2.name)
|
||||
|
||||
# partently known
|
||||
user_device3 = UserDevice.add(
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H143 Safari/600.1.4',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
nil,
|
||||
'session',
|
||||
)
|
||||
assert_equal('Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H143 Safari/600.1.4', user_device3.user_agent)
|
||||
assert_equal('iPhone', user_device3.browser)
|
||||
assert_equal('iPhone', user_device3.name)
|
||||
end
|
||||
|
||||
test 'api test' do
|
||||
|
||||
# signin with ua from country A via basic auth -> new device #1
|
||||
user_device1 = UserDevice.add(
|
||||
'curl/7.43.0',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
nil,
|
||||
'basic_auth',
|
||||
)
|
||||
|
||||
# signin with ua from country B via basic auth -> new device #2
|
||||
user_device2 = UserDevice.add(
|
||||
'curl/7.43.0',
|
||||
'176.198.137.254',
|
||||
@agent.id,
|
||||
nil,
|
||||
'basic_auth',
|
||||
)
|
||||
assert_not_equal(user_device1.id, user_device2.id)
|
||||
|
||||
# signin with ua from country A via basic auth -> new device #1
|
||||
user_device3 = UserDevice.add(
|
||||
'curl/7.43.0',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
nil,
|
||||
'basic_auth',
|
||||
)
|
||||
assert_equal(user_device1.id, user_device3.id)
|
||||
|
||||
# signin with ua from country B via basic auth -> new device #2
|
||||
user_device4 = UserDevice.add(
|
||||
'curl/7.43.0',
|
||||
'176.198.137.254',
|
||||
@agent.id,
|
||||
nil,
|
||||
'basic_auth',
|
||||
)
|
||||
assert_equal(user_device2.id, user_device4.id)
|
||||
|
||||
# signin with ua from country A via token auth -> new device #1
|
||||
user_device5 = UserDevice.add(
|
||||
'curl/7.43.0',
|
||||
'91.115.248.231',
|
||||
@agent.id,
|
||||
nil,
|
||||
'token_auth',
|
||||
)
|
||||
assert_equal(user_device1.id, user_device5.id)
|
||||
|
||||
# signin with ua from country B via token auth -> new device #2
|
||||
user_device6 = UserDevice.add(
|
||||
'curl/7.43.0',
|
||||
'176.198.137.254',
|
||||
@agent.id,
|
||||
nil,
|
||||
'token_auth',
|
||||
)
|
||||
assert_equal(user_device2.id, user_device6.id)
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
Loading…
Reference in a new issue