application_model.rb 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
  2. class ApplicationModel < ActiveRecord::Base
  3. include ApplicationModel::Assets
  4. include ApplicationModel::HistoryLogBase
  5. include ApplicationModel::ActivityStreamBase
  6. include ApplicationModel::SearchIndexBase
  7. self.abstract_class = true
  8. before_create :check_attributes_protected, :check_limits, :cache_delete, :fill_up_user_create
  9. before_update :check_limits, :fill_up_user_update
  10. before_destroy :destroy_dependencies
  11. after_create :cache_delete
  12. after_update :cache_delete
  13. after_touch :cache_delete
  14. after_destroy :cache_delete
  15. after_create :attachments_buffer_check
  16. after_update :attachments_buffer_check
  17. after_create :activity_stream_create
  18. after_update :activity_stream_update
  19. before_destroy :activity_stream_destroy
  20. after_create :history_create
  21. after_update :history_update
  22. after_destroy :history_destroy
  23. after_create :search_index_update
  24. after_update :search_index_update
  25. after_destroy :search_index_destroy
  26. before_destroy :recent_view_destroy
  27. # create instance accessor
  28. class << self
  29. attr_accessor :activity_stream_support_config, :history_support_config, :search_index_support_config
  30. end
  31. attr_accessor :history_changes_last_done
  32. def check_attributes_protected
  33. import_class_list = ['Ticket', 'Ticket::Article', 'History', 'Ticket::State', 'Ticket::StateType', 'Ticket::Priority', 'Group', 'User', 'Role' ]
  34. # do noting, use id as it is
  35. return if !Setting.get('system_init_done')
  36. return if Setting.get('import_mode') && import_class_list.include?( self.class.to_s )
  37. self[:id] = nil
  38. end
  39. =begin
  40. remove all not used model attributes of params
  41. result = Model.param_cleanup(params)
  42. for object creation, ignore id's
  43. result = Model.param_cleanup(params, true)
  44. returns
  45. result = params # params with valid attributes of model
  46. =end
  47. def self.param_cleanup(params, newObject = false)
  48. if params.nil?
  49. fail "No params for #{self}!"
  50. end
  51. # ignore id for new objects
  52. if newObject && params[:id]
  53. params[:id] = nil
  54. end
  55. # only use object attributes
  56. data = {}
  57. new.attributes.each {|item|
  58. next if !params.key?(item[0])
  59. data[item[0].to_sym] = params[item[0]]
  60. }
  61. # we do want to set this via database
  62. param_validation(data)
  63. end
  64. =begin
  65. set rellations of model based on params
  66. model = Model.find(1)
  67. result = model.param_set_associations(params)
  68. returns
  69. result = true|false
  70. =end
  71. def param_set_associations(params)
  72. # set relations
  73. self.class.reflect_on_all_associations.map { |assoc|
  74. real_key = assoc.name.to_s[0, assoc.name.to_s.length - 1] + '_ids'
  75. next if !params.key?( real_key.to_sym )
  76. list_of_items = params[ real_key.to_sym ]
  77. if params[ real_key.to_sym ].class != Array
  78. list_of_items = [ params[ real_key.to_sym ] ]
  79. end
  80. list = []
  81. list_of_items.each {|item|
  82. list.push( assoc.klass.find(item) )
  83. }
  84. send( assoc.name.to_s + '=', list )
  85. }
  86. end
  87. =begin
  88. get rellations of model based on params
  89. model = Model.find(1)
  90. attributes = model.attributes_with_associations
  91. returns
  92. hash with attributes and association ids
  93. =end
  94. def attributes_with_associations
  95. # set relations
  96. attributes = self.attributes
  97. self.class.reflect_on_all_associations.map { |assoc|
  98. real_key = assoc.name.to_s[0, assoc.name.to_s.length - 1] + '_ids'
  99. if self.respond_to?( real_key )
  100. attributes[ real_key ] = send( real_key )
  101. end
  102. }
  103. attributes
  104. end
  105. =begin
  106. remove all not used params of object (per default :updated_at, :created_at, :updated_by_id and :created_by_id)
  107. result = Model.param_validation(params)
  108. returns
  109. result = params # params without listed attributes
  110. =end
  111. def self.param_validation(data)
  112. # we do want to set this via database
  113. data.delete( :updated_at )
  114. data.delete( :created_at )
  115. data.delete( :updated_by_id )
  116. data.delete( :created_by_id )
  117. if data.respond_to?('permit!')
  118. data.permit!
  119. end
  120. data
  121. end
  122. =begin
  123. set created_by_id & updated_by_id if not given based on UserInfo (current session)
  124. Used as before_create callback, no own use needed
  125. result = Model.fill_up_user_create(params)
  126. returns
  127. result = params # params with updated_by_id & created_by_id if not given based on UserInfo (current session)
  128. =end
  129. def fill_up_user_create
  130. if self.class.column_names.include? 'updated_by_id'
  131. if UserInfo.current_user_id
  132. if updated_by_id && updated_by_id != UserInfo.current_user_id
  133. logger.info "NOTICE create - self.updated_by_id is different: #{updated_by_id}/#{UserInfo.current_user_id}"
  134. end
  135. self.updated_by_id = UserInfo.current_user_id
  136. end
  137. end
  138. return if !self.class.column_names.include? 'created_by_id'
  139. return if !UserInfo.current_user_id
  140. if created_by_id && created_by_id != UserInfo.current_user_id
  141. logger.info "NOTICE create - self.created_by_id is different: #{created_by_id}/#{UserInfo.current_user_id}"
  142. end
  143. self.created_by_id = UserInfo.current_user_id
  144. end
  145. =begin
  146. set updated_by_id if not given based on UserInfo (current session)
  147. Used as before_update callback, no own use needed
  148. result = Model.fill_up_user_update(params)
  149. returns
  150. result = params # params with updated_by_id & created_by_id if not given based on UserInfo (current session)
  151. =end
  152. def fill_up_user_update
  153. return if !self.class.column_names.include? 'updated_by_id'
  154. return if !UserInfo.current_user_id
  155. self.updated_by_id = UserInfo.current_user_id
  156. end
  157. def cache_update(o)
  158. cache_delete if self.respond_to?('cache_delete')
  159. o.cache_delete if o.respond_to?('cache_delete')
  160. end
  161. def cache_delete
  162. # delete id caches
  163. key = self.class.to_s + '::' + id.to_s
  164. Cache.delete( key.to_s )
  165. key = self.class.to_s + ':f:' + id.to_s
  166. Cache.delete( key.to_s )
  167. # delete old name / login caches
  168. if self.changed?
  169. if changes.key?('name')
  170. name = changes['name'][0].to_s
  171. key = self.class.to_s + '::' + name
  172. Cache.delete( key.to_s )
  173. key = self.class.to_s + ':f:' + name
  174. Cache.delete( key.to_s )
  175. end
  176. if changes.key?('login')
  177. name = changes['login'][0].to_s
  178. key = self.class.to_s + '::' + name
  179. Cache.delete( key.to_s )
  180. key = self.class.to_s + ':f:' + name
  181. Cache.delete( key.to_s )
  182. end
  183. end
  184. # delete name / login caches
  185. if self[:name]
  186. key = self.class.to_s + '::' + self.name.to_s
  187. Cache.delete( key.to_s )
  188. key = self.class.to_s + ':f:' + self.name.to_s
  189. Cache.delete( key.to_s )
  190. end
  191. return if !self[:login]
  192. key = self.class.to_s + '::' + login.to_s
  193. Cache.delete( key.to_s )
  194. key = self.class.to_s + ':f:' + login.to_s
  195. Cache.delete( key.to_s )
  196. end
  197. def self.cache_set(data_id, data, full = false)
  198. if !full
  199. key = to_s + '::' + data_id.to_s
  200. else
  201. key = to_s + ':f:' + data_id.to_s
  202. end
  203. Cache.write( key.to_s, data )
  204. end
  205. def self.cache_get(data_id, full = false)
  206. if !full
  207. key = to_s + '::' + data_id.to_s
  208. else
  209. key = to_s + ':f:' + data_id.to_s
  210. end
  211. Cache.get( key.to_s )
  212. end
  213. =begin
  214. lookup model from cache (if exists) or retrieve it from db, id, name or login possible
  215. result = Model.lookup( :id => 123 )
  216. result = Model.lookup( :name => 'some name' )
  217. result = Model.lookup( :login => 'some login' )
  218. returns
  219. result = model # with all attributes
  220. =end
  221. def self.lookup(data)
  222. if data[:id]
  223. cache = cache_get( data[:id] )
  224. return cache if cache
  225. record = find_by( id: data[:id] )
  226. cache_set( data[:id], record )
  227. return record
  228. elsif data[:name]
  229. cache = cache_get( data[:name] )
  230. return cache if cache
  231. records = where( name: data[:name] )
  232. records.each {|loop_record|
  233. if loop_record.name == data[:name]
  234. cache_set( data[:name], loop_record )
  235. return loop_record
  236. end
  237. }
  238. return
  239. elsif data[:login]
  240. cache = cache_get( data[:login] )
  241. return cache if cache
  242. records = where( login: data[:login] )
  243. records.each {|loop_record|
  244. if loop_record.login == data[:login]
  245. cache_set( data[:login], loop_record )
  246. return loop_record
  247. end
  248. }
  249. return
  250. else
  251. fail 'Need name, id or login for lookup()'
  252. end
  253. end
  254. =begin
  255. create model if not exists (check exists based on id, name, login or locale)
  256. result = Model.create_if_not_exists( attributes )
  257. returns
  258. result = model # with all attributes
  259. =end
  260. def self.create_if_not_exists(data)
  261. if data[:id]
  262. record = find_by( id: data[:id] )
  263. return record if record
  264. elsif data[:name]
  265. records = where( name: data[:name] )
  266. records.each {|loop_record|
  267. return loop_record if loop_record.name == data[:name]
  268. }
  269. elsif data[:login]
  270. records = where( login: data[:login] )
  271. records.each {|loop_record|
  272. return loop_record if loop_record.login == data[:login]
  273. }
  274. elsif data[:locale] && data[:source]
  275. records = where( locale: data[:locale], source: data[:source] )
  276. records.each {|loop_record|
  277. return loop_record if loop_record.source == data[:source]
  278. }
  279. end
  280. create(data)
  281. end
  282. =begin
  283. create or update model (check exists based on id, name, login or locale)
  284. result = Model.create_or_update( attributes )
  285. returns
  286. result = model # with all attributes
  287. =end
  288. def self.create_or_update(data)
  289. if data[:id]
  290. records = where( id: data[:id] )
  291. records.each {|loop_record|
  292. loop_record.update_attributes( data )
  293. return loop_record
  294. }
  295. record = new( data )
  296. record.save
  297. return record
  298. elsif data[:name]
  299. records = where( name: data[:name] )
  300. records.each {|loop_record|
  301. if loop_record.name == data[:name]
  302. loop_record.update_attributes( data )
  303. return loop_record
  304. end
  305. }
  306. record = new( data )
  307. record.save
  308. return record
  309. elsif data[:login]
  310. records = where( login: data[:login] )
  311. records.each {|loop_record|
  312. if loop_record.login.downcase == data[:login].downcase
  313. loop_record.update_attributes( data )
  314. return loop_record
  315. end
  316. }
  317. record = new( data )
  318. record.save
  319. return record
  320. elsif data[:locale]
  321. records = where( locale: data[:locale] )
  322. records.each {|loop_record|
  323. if loop_record.locale.downcase == data[:locale].downcase
  324. loop_record.update_attributes( data )
  325. return loop_record
  326. end
  327. }
  328. record = new( data )
  329. record.save
  330. return record
  331. else
  332. fail 'Need name, login or locale for create_or_update()'
  333. end
  334. end
  335. =begin
  336. activate latest change on create, update, touch and destroy
  337. class Model < ApplicationModel
  338. latest_change_support
  339. end
  340. =end
  341. def self.latest_change_support
  342. after_create :latest_change_set_from_observer
  343. after_update :latest_change_set_from_observer
  344. after_touch :latest_change_set_from_observer
  345. after_destroy :latest_change_set_from_observer_destroy
  346. end
  347. def latest_change_set_from_observer
  348. self.class.latest_change_set(updated_at)
  349. end
  350. def latest_change_set_from_observer_destroy
  351. self.class.latest_change_set(nil)
  352. end
  353. def self.latest_change_set(updated_at)
  354. key = "#{new.class.name}_latest_change"
  355. expires_in = 31_536_000 # 1 year
  356. if updated_at.nil?
  357. Cache.delete( key )
  358. else
  359. Cache.write( key, updated_at, { expires_in: expires_in } )
  360. end
  361. end
  362. =begin
  363. get latest updated_at object timestamp
  364. latest_change = Ticket.latest_change
  365. returns
  366. result = timestamp
  367. =end
  368. def self.latest_change
  369. key = "#{new.class.name}_latest_change"
  370. updated_at = Cache.get( key )
  371. # if we do not have it cached, do lookup
  372. if !updated_at
  373. o = select(:updated_at).order(updated_at: :desc).limit(1).first
  374. if o
  375. updated_at = o.updated_at
  376. latest_change_set(updated_at)
  377. end
  378. end
  379. updated_at
  380. end
  381. =begin
  382. activate client notify support on create, update, touch and destroy
  383. class Model < ApplicationModel
  384. notify_clients_support
  385. end
  386. =end
  387. def self.notify_clients_support
  388. after_create :notify_clients_after_create
  389. after_update :notify_clients_after_update
  390. after_touch :notify_clients_after_touch
  391. after_destroy :notify_clients_after_destroy
  392. end
  393. =begin
  394. notify_clients_after_create after model got created
  395. used as callback in model file
  396. class OwnModel < ApplicationModel
  397. after_create :notify_clients_after_create
  398. after_update :notify_clients_after_update
  399. after_touch :notify_clients_after_touch
  400. after_destroy :notify_clients_after_destroy
  401. [...]
  402. =end
  403. def notify_clients_after_create
  404. # return if we run import mode
  405. return if Setting.get('import_mode')
  406. logger.debug "#{ self.class.name }.find(#{ id }) notify created " + created_at.to_s
  407. class_name = self.class.name
  408. class_name.gsub!(/::/, '')
  409. Sessions.broadcast(
  410. event: class_name + ':create',
  411. data: { id: id, updated_at: updated_at }
  412. )
  413. end
  414. =begin
  415. notify_clients_after_update after model got updated
  416. used as callback in model file
  417. class OwnModel < ApplicationModel
  418. after_create :notify_clients_after_create
  419. after_update :notify_clients_after_update
  420. after_touch :notify_clients_after_touch
  421. after_destroy :notify_clients_after_destroy
  422. [...]
  423. =end
  424. def notify_clients_after_update
  425. # return if we run import mode
  426. return if Setting.get('import_mode')
  427. logger.debug "#{ self.class.name }.find(#{ id }) notify UPDATED " + updated_at.to_s
  428. class_name = self.class.name
  429. class_name.gsub!(/::/, '')
  430. Sessions.broadcast(
  431. event: class_name + ':update',
  432. data: { id: id, updated_at: updated_at }
  433. )
  434. end
  435. =begin
  436. notify_clients_after_touch after model got touched
  437. used as callback in model file
  438. class OwnModel < ApplicationModel
  439. after_create :notify_clients_after_create
  440. after_update :notify_clients_after_update
  441. after_touch :notify_clients_after_touch
  442. after_destroy :notify_clients_after_destroy
  443. [...]
  444. =end
  445. def notify_clients_after_touch
  446. # return if we run import mode
  447. return if Setting.get('import_mode')
  448. logger.debug "#{ self.class.name }.find(#{ id }) notify TOUCH " + updated_at.to_s
  449. class_name = self.class.name
  450. class_name.gsub!(/::/, '')
  451. Sessions.broadcast(
  452. event: class_name + ':touch',
  453. data: { id: id, updated_at: updated_at }
  454. )
  455. end
  456. =begin
  457. notify_clients_after_destroy after model got destroyed
  458. used as callback in model file
  459. class OwnModel < ApplicationModel
  460. after_create :notify_clients_after_create
  461. after_update :notify_clients_after_update
  462. after_touch :notify_clients_after_touch
  463. after_destroy :notify_clients_after_destroy
  464. [...]
  465. =end
  466. def notify_clients_after_destroy
  467. # return if we run import mode
  468. return if Setting.get('import_mode')
  469. logger.debug "#{ self.class.name }.find(#{ id }) notify DESTOY " + updated_at.to_s
  470. class_name = self.class.name
  471. class_name.gsub!(/::/, '')
  472. Sessions.broadcast(
  473. event: class_name + ':destroy',
  474. data: { id: id, updated_at: updated_at }
  475. )
  476. end
  477. =begin
  478. serve methode to configure and enable search index support for this model
  479. class Model < ApplicationModel
  480. search_index_support :ignore_attributes => {
  481. :create_article_type_id => true,
  482. :create_article_sender_id => true,
  483. :article_count => true,
  484. }
  485. end
  486. =end
  487. def self.search_index_support(data = {})
  488. @search_index_support_config = data
  489. end
  490. =begin
  491. update search index, if configured - will be executed automatically
  492. model = Model.find(123)
  493. model.search_index_update
  494. =end
  495. def search_index_update
  496. return if !self.class.search_index_support_config
  497. # start background job to transfer data to search index
  498. return if !SearchIndexBackend.enabled?
  499. Delayed::Job.enqueue( ApplicationModel::BackgroundJobSearchIndex.new( self.class.to_s, id ) )
  500. end
  501. =begin
  502. delete search index object, will be executed automatically
  503. model = Model.find(123)
  504. model.search_index_destroy
  505. =end
  506. def search_index_destroy
  507. return if !self.class.search_index_support_config
  508. SearchIndexBackend.remove( self.class.to_s, id )
  509. end
  510. =begin
  511. reload search index with full data
  512. Model.search_index_reload
  513. =end
  514. def self.search_index_reload
  515. return if !@search_index_support_config
  516. all_ids = select('id').all.order('created_at DESC')
  517. all_ids.each { |item_with_id|
  518. item = find( item_with_id.id )
  519. item.search_index_update_backend
  520. }
  521. end
  522. =begin
  523. serve methode to configure and enable activity stream support for this model
  524. class Model < ApplicationModel
  525. activity_stream_support :role => 'Admin'
  526. end
  527. =end
  528. def self.activity_stream_support(data = {})
  529. @activity_stream_support_config = data
  530. end
  531. =begin
  532. log object create activity stream, if configured - will be executed automatically
  533. model = Model.find(123)
  534. model.activity_stream_create
  535. =end
  536. def activity_stream_create
  537. return if !self.class.activity_stream_support_config
  538. activity_stream_log( 'created', self['created_by_id'] )
  539. end
  540. =begin
  541. log object update activity stream, if configured - will be executed automatically
  542. model = Model.find(123)
  543. model.activity_stream_update
  544. =end
  545. def activity_stream_update
  546. return if !self.class.activity_stream_support_config
  547. return if !self.changed?
  548. # default ignored attributes
  549. ignore_attributes = {
  550. created_at: true,
  551. updated_at: true,
  552. created_by_id: true,
  553. updated_by_id: true,
  554. }
  555. if self.class.activity_stream_support_config[:ignore_attributes]
  556. self.class.activity_stream_support_config[:ignore_attributes].each {|key, value|
  557. ignore_attributes[key] = value
  558. }
  559. end
  560. log = false
  561. changes.each {|key, _value|
  562. # do not log created_at and updated_at attributes
  563. next if ignore_attributes[key.to_sym] == true
  564. log = true
  565. }
  566. return if !log
  567. activity_stream_log( 'updated', self['updated_by_id'] )
  568. end
  569. =begin
  570. delete object activity stream, will be executed automatically
  571. model = Model.find(123)
  572. model.activity_stream_destroy
  573. =end
  574. def activity_stream_destroy
  575. return if !self.class.activity_stream_support_config
  576. ActivityStream.remove( self.class.to_s, id )
  577. end
  578. =begin
  579. serve methode to configure and enable history support for this model
  580. class Model < ApplicationModel
  581. history_support
  582. end
  583. class Model < ApplicationModel
  584. history_support :ignore_attributes => { :article_count => true }
  585. end
  586. =end
  587. def self.history_support(data = {})
  588. @history_support_config = data
  589. end
  590. =begin
  591. log object create history, if configured - will be executed automatically
  592. model = Model.find(123)
  593. model.history_create
  594. =end
  595. def history_create
  596. return if !self.class.history_support_config
  597. #logger.debug 'create ' + self.changes.inspect
  598. history_log( 'created', created_by_id )
  599. end
  600. =begin
  601. log object update history with all updated attributes, if configured - will be executed automatically
  602. model = Model.find(123)
  603. model.history_update
  604. =end
  605. def history_update
  606. return if !self.class.history_support_config
  607. return if !self.changed?
  608. # return if it's no update
  609. return if self.new_record?
  610. # new record also triggers update, so ignore new records
  611. changes = self.changes
  612. if history_changes_last_done
  613. history_changes_last_done.each {|key, value|
  614. if changes.key?(key) && changes[key] == value
  615. changes.delete(key)
  616. end
  617. }
  618. end
  619. self.history_changes_last_done = changes
  620. #logger.info 'updated ' + self.changes.inspect
  621. return if changes['id'] && !changes['id'][0]
  622. # default ignored attributes
  623. ignore_attributes = {
  624. created_at: true,
  625. updated_at: true,
  626. created_by_id: true,
  627. updated_by_id: true,
  628. }
  629. if self.class.history_support_config[:ignore_attributes]
  630. self.class.history_support_config[:ignore_attributes].each {|key, value|
  631. ignore_attributes[key] = value
  632. }
  633. end
  634. changes.each {|key, value|
  635. # do not log created_at and updated_at attributes
  636. next if ignore_attributes[key.to_sym] == true
  637. # get attribute name
  638. attribute_name = key.to_s
  639. if attribute_name[-3, 3] == '_id'
  640. attribute_name = attribute_name[ 0, attribute_name.length - 3 ]
  641. end
  642. value_id = []
  643. value_str = [ value[0], value[1] ]
  644. if key.to_s[-3, 3] == '_id'
  645. value_id[0] = value[0]
  646. value_id[1] = value[1]
  647. if self.respond_to?( attribute_name ) && send(attribute_name)
  648. relation_class = send(attribute_name).class
  649. if relation_class && value_id[0]
  650. relation_model = relation_class.lookup( id: value_id[0] )
  651. if relation_model
  652. if relation_model['name']
  653. value_str[0] = relation_model['name']
  654. elsif relation_model.respond_to?('fullname')
  655. value_str[0] = relation_model.send('fullname')
  656. end
  657. end
  658. end
  659. if relation_class && value_id[1]
  660. relation_model = relation_class.lookup( id: value_id[1] )
  661. if relation_model
  662. if relation_model['name']
  663. value_str[1] = relation_model['name']
  664. elsif relation_model.respond_to?('fullname')
  665. value_str[1] = relation_model.send('fullname')
  666. end
  667. end
  668. end
  669. end
  670. end
  671. data = {
  672. history_attribute: attribute_name,
  673. value_from: value_str[0].to_s,
  674. value_to: value_str[1].to_s,
  675. id_from: value_id[0],
  676. id_to: value_id[1],
  677. }
  678. #logger.info "HIST NEW #{self.class.to_s}.find(#{self.id}) #{data.inspect}"
  679. history_log( 'updated', updated_by_id, data )
  680. }
  681. end
  682. =begin
  683. delete object history, will be executed automatically
  684. model = Model.find(123)
  685. model.history_destroy
  686. =end
  687. def history_destroy
  688. return if !self.class.history_support_config
  689. History.remove( self.class.to_s, id )
  690. end
  691. =begin
  692. get list of attachments of this object
  693. item = Model.find(123)
  694. list = item.attachments
  695. returns
  696. # array with Store model objects
  697. =end
  698. def attachments
  699. Store.list( object: self.class.to_s, o_id: id )
  700. end
  701. =begin
  702. store attachments for this object
  703. item = Model.find(123)
  704. item.attachments = [ Store-Object1, Store-Object2 ]
  705. =end
  706. def attachments=(attachments)
  707. self.attachments_buffer = attachments
  708. # update if object already exists
  709. return if !( id && id != 0 )
  710. attachments_buffer_check
  711. end
  712. =begin
  713. return object and assets
  714. data = Model.full(123)
  715. data = {
  716. :id => 123,
  717. :assets => assets,
  718. }
  719. =end
  720. def self.full(id)
  721. object = find(id)
  722. assets = object.assets({})
  723. {
  724. id: id,
  725. assets: assets,
  726. }
  727. end
  728. =begin
  729. get assets of object list
  730. list = [
  731. {
  732. object => 'Ticket',
  733. o_id => 1,
  734. },
  735. {
  736. object => 'User',
  737. o_id => 121,
  738. },
  739. ]
  740. assets = Model.assets_of_object_list(list, assets)
  741. =end
  742. def self.assets_of_object_list(list, assets = {})
  743. list.each {|item|
  744. require item['object'].to_filename
  745. record = Kernel.const_get( item['object'] ).find( item['o_id'] )
  746. assets = record.assets(assets)
  747. if item['created_by_id']
  748. user = User.find( item['created_by_id'] )
  749. assets = user.assets(assets)
  750. end
  751. if item['updated_by_id']
  752. user = User.find( item['updated_by_id'] )
  753. assets = user.assets(assets)
  754. end
  755. }
  756. assets
  757. end
  758. private
  759. def attachments_buffer
  760. @attachments_buffer_data
  761. end
  762. def attachments_buffer=(attachments)
  763. @attachments_buffer_data = attachments
  764. end
  765. def attachments_buffer_check
  766. # do nothing if no attachment exists
  767. return 1 if attachments_buffer.nil?
  768. # store attachments
  769. article_store = []
  770. attachments_buffer.each do |attachment|
  771. article_store.push Store.add(
  772. object: self.class.to_s,
  773. o_id: id,
  774. data: attachment.content,
  775. filename: attachment.filename,
  776. preferences: attachment.preferences,
  777. created_by_id: created_by_id,
  778. )
  779. end
  780. attachments_buffer = nil
  781. end
  782. =begin
  783. delete object recent viewed list, will be executed automatically
  784. model = Model.find(123)
  785. model.recent_view_destroy
  786. =end
  787. def recent_view_destroy
  788. RecentView.log_destroy( self.class.to_s, id )
  789. end
  790. =begin
  791. check string/varchar size and cut them if needed
  792. =end
  793. def check_limits
  794. attributes.each {|attribute|
  795. next if !self[ attribute[0] ]
  796. next if self[ attribute[0] ].class != String
  797. next if self[ attribute[0] ].empty?
  798. column = self.class.columns_hash[ attribute[0] ]
  799. limit = column.limit
  800. if column && limit
  801. current_length = attribute[1].to_s.length
  802. if limit < current_length
  803. logger.warn "WARNING: cut string because of database length #{self.class}.#{attribute[0]}(#{limit} but is #{current_length}:#{attribute[1]})"
  804. self[ attribute[0] ] = attribute[1][ 0, limit ]
  805. end
  806. end
  807. # strip 4 bytes utf8 chars if needed
  808. if column && self[ attribute[0] ]
  809. self[attribute[0]] = self[ attribute[0] ].utf8_to_3bytesutf8
  810. end
  811. }
  812. end
  813. =begin
  814. destory object dependencies, will be executed automatically
  815. =end
  816. def destroy_dependencies
  817. end
  818. end