tickets_controller.rb 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
  2. class TicketsController < ApplicationController
  3. before_action :authentication_check
  4. # GET /api/v1/tickets/1
  5. def show
  6. @ticket = Ticket.find( params[:id] )
  7. # permission check
  8. return if !ticket_permission(@ticket)
  9. render json: @ticket
  10. end
  11. # POST /api/v1/tickets
  12. def create
  13. ticket = Ticket.new( Ticket.param_validation( params[:ticket] ) )
  14. # check if article is given
  15. if !params[:article]
  16. render json: 'article hash is missing', status: :unprocessable_entity
  17. return
  18. end
  19. # create ticket
  20. if !ticket.save
  21. render json: ticket.errors, status: :unprocessable_entity
  22. return
  23. end
  24. # create tags if given
  25. if params[:tags] && !params[:tags].empty?
  26. tags = params[:tags].split(/,/)
  27. tags.each {|tag|
  28. Tag.tag_add(
  29. object: 'Ticket',
  30. o_id: ticket.id,
  31. item: tag,
  32. created_by_id: current_user.id,
  33. )
  34. }
  35. end
  36. # create article if given
  37. if params[:article]
  38. article_create( ticket, params[:article] )
  39. end
  40. render json: ticket, status: :created
  41. end
  42. # PUT /api/v1/tickets/1
  43. def update
  44. ticket = Ticket.find(params[:id])
  45. # permission check
  46. return if !ticket_permission(ticket)
  47. if ticket.update_attributes( Ticket.param_validation( params[:ticket] ) )
  48. if params[:article]
  49. article_create( ticket, params[:article] )
  50. end
  51. render json: ticket, status: :ok
  52. else
  53. render json: ticket.errors, status: :unprocessable_entity
  54. end
  55. end
  56. # DELETE /api/v1/tickets/1
  57. def destroy
  58. ticket = Ticket.find( params[:id] )
  59. # permission check
  60. return if !ticket_permission(ticket)
  61. ticket.destroy
  62. head :ok
  63. end
  64. # GET /api/v1/ticket_customer
  65. # GET /api/v1/tickets_customer
  66. def ticket_customer
  67. # return result
  68. result = Ticket::ScreenOptions.list_by_customer(
  69. customer_id: params[:customer_id],
  70. limit: 15,
  71. )
  72. render json: result
  73. end
  74. # GET /api/v1/ticket_history/1
  75. def ticket_history
  76. # get ticket data
  77. ticket = Ticket.find( params[:id] )
  78. # permission check
  79. return if !ticket_permission( ticket )
  80. # get history of ticket
  81. history = ticket.history_get(true)
  82. # return result
  83. render json: history
  84. end
  85. # GET /api/v1/ticket_related/1
  86. def ticket_related
  87. ticket = Ticket.find( params[:ticket_id] )
  88. assets = ticket.assets({})
  89. # open tickets by customer
  90. group_ids = Group.select( 'groups.id' )
  91. .joins(:users)
  92. .where( 'groups_users.user_id = ?', current_user.id )
  93. .where( 'groups.active = ?', true )
  94. .map( &:id )
  95. access_condition = [ 'group_id IN (?)', group_ids ]
  96. ticket_lists = Ticket
  97. .where(
  98. customer_id: ticket.customer_id,
  99. state_id: Ticket::State.by_category( 'open' )
  100. )
  101. .where(access_condition)
  102. .where( 'id != ?', [ ticket.id ] )
  103. .order('created_at DESC')
  104. .limit(6)
  105. # get related assets
  106. ticket_ids_by_customer = []
  107. ticket_lists.each {|ticket_list|
  108. ticket_ids_by_customer.push ticket_list.id
  109. assets = ticket_list.assets(assets)
  110. }
  111. ticket_ids_recent_viewed = []
  112. recent_views = RecentView.list( current_user, 8, 'Ticket' )
  113. recent_views.each {|recent_view|
  114. next if recent_view['object'] != 'Ticket'
  115. ticket_ids_recent_viewed.push recent_view['o_id']
  116. recent_view_ticket = Ticket.find( recent_view['o_id'] )
  117. assets = recent_view_ticket.assets(assets)
  118. }
  119. # return result
  120. render json: {
  121. assets: assets,
  122. ticket_ids_by_customer: ticket_ids_by_customer,
  123. ticket_ids_recent_viewed: ticket_ids_recent_viewed,
  124. }
  125. end
  126. # GET /api/v1/ticket_merge/1/1
  127. def ticket_merge
  128. # check master ticket
  129. ticket_master = Ticket.find_by(number: params[:master_ticket_number])
  130. if !ticket_master
  131. render json: {
  132. result: 'faild',
  133. message: 'No such master ticket number!',
  134. }
  135. return
  136. end
  137. # permission check
  138. return if !ticket_permission(ticket_master)
  139. # check slave ticket
  140. ticket_slave = Ticket.find_by(id: params[:slave_ticket_id] )
  141. if !ticket_slave
  142. render json: {
  143. result: 'faild',
  144. message: 'No such slave ticket!',
  145. }
  146. return
  147. end
  148. # permission check
  149. return if !ticket_permission( ticket_slave )
  150. # check diffetent ticket ids
  151. if ticket_slave.id == ticket_master.id
  152. render json: {
  153. result: 'faild',
  154. message: 'Can\'t merge ticket with it self!',
  155. }
  156. return
  157. end
  158. # merge ticket
  159. ticket_slave.merge_to(
  160. ticket_id: ticket_master.id,
  161. created_by_id: current_user.id,
  162. )
  163. # return result
  164. render json: {
  165. result: 'success',
  166. master_ticket: ticket_master.attributes,
  167. slave_ticket: ticket_slave.attributes,
  168. }
  169. end
  170. # GET /api/v1/ticket_full/1
  171. def ticket_full
  172. # permission check
  173. ticket = Ticket.find( params[:id] )
  174. return if !ticket_permission(ticket)
  175. # get attributes to update
  176. attributes_to_change = Ticket::ScreenOptions.attributes_to_change(user: current_user, ticket: ticket)
  177. # get related users
  178. assets = attributes_to_change[:assets]
  179. assets = ticket.assets(assets)
  180. # get related articles
  181. articles = Ticket::Article.where(ticket_id: params[:id])
  182. # get related users
  183. article_ids = []
  184. articles.each {|article|
  185. # ignore internal article if customer is requesting
  186. next if article.internal == true && role?(Z_ROLENAME_CUSTOMER)
  187. # load article ids
  188. article_ids.push article.id
  189. # load assets
  190. assets = article.assets(assets)
  191. }
  192. # get links
  193. links = Link.list(
  194. link_object: 'Ticket',
  195. link_object_value: ticket.id,
  196. )
  197. link_list = []
  198. links.each { |item|
  199. link_list.push item
  200. if item['link_object'] == 'Ticket'
  201. linked_ticket = Ticket.lookup( id: item['link_object_value'] )
  202. assets = linked_ticket.assets(assets)
  203. end
  204. }
  205. # get tags
  206. tags = Tag.tag_list(
  207. object: 'Ticket',
  208. o_id: ticket.id,
  209. )
  210. # return result
  211. render json: {
  212. ticket_id: ticket.id,
  213. ticket_article_ids: article_ids,
  214. assets: assets,
  215. links: link_list,
  216. tags: tags,
  217. form_meta: attributes_to_change[:form_meta],
  218. }
  219. end
  220. # GET /api/v1/ticket_split
  221. def ticket_split
  222. # permission check
  223. ticket = Ticket.find(params[:ticket_id])
  224. return if !ticket_permission(ticket)
  225. assets = ticket.assets({})
  226. # get related articles
  227. article = Ticket::Article.find(params[:article_id])
  228. assets = article.assets(assets)
  229. render json: {
  230. assets: assets
  231. }
  232. end
  233. # GET /api/v1/ticket_create
  234. def ticket_create
  235. # get attributes to update
  236. attributes_to_change = Ticket::ScreenOptions.attributes_to_change(
  237. user: current_user,
  238. )
  239. render json: attributes_to_change
  240. end
  241. # GET /api/v1/tickets/search
  242. def search
  243. # permit nested conditions
  244. params.require(:condition).permit!
  245. # build result list
  246. tickets = Ticket.search(
  247. limit: params[:limit],
  248. query: params[:term],
  249. condition: params[:condition],
  250. current_user: current_user,
  251. )
  252. assets = {}
  253. ticket_result = []
  254. tickets.each do |ticket|
  255. ticket_result.push ticket.id
  256. assets = ticket.assets(assets)
  257. end
  258. # return result
  259. render json: {
  260. tickets: ticket_result,
  261. tickets_count: tickets.count,
  262. assets: assets,
  263. }
  264. end
  265. # GET /api/v1/tickets/selector
  266. def selector
  267. return if deny_if_not_role(Z_ROLENAME_ADMIN)
  268. ticket_count, tickets = Ticket.selectors(params[:condition], 6)
  269. assets = {}
  270. ticket_ids = []
  271. if tickets
  272. tickets.each do |ticket|
  273. ticket_ids.push ticket.id
  274. assets = ticket.assets(assets)
  275. end
  276. end
  277. # return result
  278. render json: {
  279. ticket_ids: ticket_ids,
  280. ticket_count: ticket_count || 0,
  281. assets: assets,
  282. }
  283. end
  284. # GET /api/v1/ticket_stats
  285. def stats
  286. if !params[:user_id] && !params[:organization_id]
  287. raise 'Need user_id or organization_id as param'
  288. end
  289. # permission check
  290. #return if !ticket_permission(ticket)
  291. # lookup open user tickets
  292. limit = 100
  293. assets = {}
  294. access_condition = Ticket.access_condition(current_user)
  295. now = Time.zone.now
  296. user_tickets_open_ids = []
  297. user_tickets_closed_ids = []
  298. user_ticket_volume_by_year = []
  299. if params[:user_id]
  300. user = User.lookup(id: params[:user_id])
  301. condition = {
  302. 'ticket.state_id' => {
  303. operator: 'is',
  304. value: Ticket::State.by_category('open').map(&:id),
  305. },
  306. 'ticket.customer_id' => {
  307. operator: 'is',
  308. value: user.id,
  309. },
  310. }
  311. user_tickets_open = Ticket.search(
  312. limit: limit,
  313. condition: condition,
  314. current_user: current_user,
  315. )
  316. user_tickets_open_ids = assets_of_tickets(user_tickets_open, assets)
  317. # lookup closed user tickets
  318. condition = {
  319. 'ticket.state_id' => {
  320. operator: 'is',
  321. value: Ticket::State.by_category('closed').map(&:id),
  322. },
  323. 'ticket.customer_id' => {
  324. operator: 'is',
  325. value: user.id,
  326. },
  327. }
  328. user_tickets_closed = Ticket.search(
  329. limit: limit,
  330. condition: condition,
  331. current_user: current_user,
  332. )
  333. user_tickets_closed_ids = assets_of_tickets(user_tickets_closed, assets)
  334. # generate stats by user
  335. (0..11).each {|month_back|
  336. date_to_check = now - month_back.month
  337. date_start = "#{date_to_check.year}-#{date_to_check.month}-01 00:00:00"
  338. date_end = "#{date_to_check.year}-#{date_to_check.month}-#{date_to_check.end_of_month.day} 00:00:00"
  339. condition = {
  340. 'tickets.customer_id' => user.id,
  341. }
  342. # created
  343. created = Ticket.where('created_at > ? AND created_at < ?', date_start, date_end )
  344. .where(access_condition)
  345. .where(condition)
  346. .count
  347. # closed
  348. closed = Ticket.where('close_time > ? AND close_time < ?', date_start, date_end )
  349. .where(access_condition)
  350. .where(condition)
  351. .count
  352. data = {
  353. month: date_to_check.month,
  354. year: date_to_check.year,
  355. text: Date::MONTHNAMES[date_to_check.month],
  356. created: created,
  357. closed: closed,
  358. }
  359. user_ticket_volume_by_year.push data
  360. }
  361. end
  362. # lookup open org tickets
  363. org_tickets_open_ids = []
  364. org_tickets_closed_ids = []
  365. org_ticket_volume_by_year = []
  366. if params[:organization_id] && !params[:organization_id].empty?
  367. condition = {
  368. 'ticket.state_id' => {
  369. operator: 'is',
  370. value: Ticket::State.by_category('open').map(&:id),
  371. },
  372. 'ticket.organization_id' => {
  373. operator: 'is',
  374. value: params[:organization_id],
  375. },
  376. }
  377. org_tickets_open = Ticket.search(
  378. limit: limit,
  379. condition: condition,
  380. current_user: current_user,
  381. )
  382. org_tickets_open_ids = assets_of_tickets(org_tickets_open, assets)
  383. # lookup closed org tickets
  384. condition = {
  385. 'ticket.state_id' => {
  386. operator: 'is',
  387. value: Ticket::State.by_category('closed').map(&:id),
  388. },
  389. 'ticket.organization_id' => {
  390. operator: 'is',
  391. value: params[:organization_id],
  392. },
  393. }
  394. org_tickets_closed = Ticket.search(
  395. limit: limit,
  396. condition: condition,
  397. current_user: current_user,
  398. )
  399. org_tickets_closed_ids = assets_of_tickets(org_tickets_closed, assets)
  400. # generate stats by org
  401. (0..11).each {|month_back|
  402. date_to_check = now - month_back.month
  403. date_start = "#{date_to_check.year}-#{date_to_check.month}-01 00:00:00"
  404. date_end = "#{date_to_check.year}-#{date_to_check.month}-#{date_to_check.end_of_month.day} 00:00:00"
  405. condition = {
  406. 'tickets.organization_id' => params[:organization_id],
  407. }
  408. # created
  409. created = Ticket.where('created_at > ? AND created_at < ?', date_start, date_end ).where(condition).count
  410. # closed
  411. closed = Ticket.where('close_time > ? AND close_time < ?', date_start, date_end ).where(condition).count
  412. data = {
  413. month: date_to_check.month,
  414. year: date_to_check.year,
  415. text: Date::MONTHNAMES[date_to_check.month],
  416. created: created,
  417. closed: closed,
  418. }
  419. org_ticket_volume_by_year.push data
  420. }
  421. end
  422. # return result
  423. render json: {
  424. user_tickets_open_ids: user_tickets_open_ids,
  425. user_tickets_closed_ids: user_tickets_closed_ids,
  426. org_tickets_open_ids: org_tickets_open_ids,
  427. org_tickets_closed_ids: org_tickets_closed_ids,
  428. user_ticket_volume_by_year: user_ticket_volume_by_year,
  429. org_ticket_volume_by_year: org_ticket_volume_by_year,
  430. assets: assets,
  431. }
  432. end
  433. private
  434. def assets_of_tickets(tickets, assets)
  435. ticket_ids = []
  436. tickets.each do |ticket|
  437. ticket_ids.push ticket.id
  438. assets = ticket.assets(assets)
  439. end
  440. ticket_ids
  441. end
  442. def article_create(ticket, params)
  443. # create article if given
  444. form_id = params[:form_id]
  445. params.delete(:form_id)
  446. article = Ticket::Article.new( Ticket::Article.param_validation( params ) )
  447. article.ticket_id = ticket.id
  448. # find attachments in upload cache
  449. if form_id
  450. article.attachments = Store.list(
  451. object: 'UploadCache',
  452. o_id: form_id,
  453. )
  454. end
  455. if !article.save
  456. render json: article.errors, status: :unprocessable_entity
  457. return
  458. end
  459. # remove attachments from upload cache
  460. return if !form_id
  461. Store.remove(
  462. object: 'UploadCache',
  463. o_id: form_id,
  464. )
  465. end
  466. end