lita-pagerduty 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c1976196f33f4a430eff395034fd70aeb5ad0ade
4
- data.tar.gz: 59f6a07f7e158675e73c5729241adf9d4dc3bc8c
3
+ metadata.gz: 995b4cc2ce45f281596f3db0ad7e743b41366f78
4
+ data.tar.gz: c372723772d7453a7d61433a35cabd21d2b55496
5
5
  SHA512:
6
- metadata.gz: dbc56aedef1af70d73ce6bdb4cc50c6794c1e48e446f06e7727567a3f5a8b75a828b609768145c8d0dcd6c063ebae756793d28e694158a041e55de16974678c0
7
- data.tar.gz: 5e60c4a48e19be645a661c8e91dfd3cd1e2fb01cbb940f78719d935a14e4245dfe6f1723aa759cb7313440922848c4c2bbc895382353510114dd7b9f1e3cb72d
6
+ metadata.gz: fe7ab1d8f578117c52e61d6485e7a9a28af17232cc97d6a62f1ff12a782e390669783a9b4064c2f35a65fa19d874c9519a013b2949dba5a6ca9a884500cc5a63
7
+ data.tar.gz: e795ce52f3318fc166f85d8b1229eddcfdf915a063aef9006d0b3cc2ad37072c82ff8196f2b58d95253d228ce78107d3328b0d4fb4e12a78ba5d792a85ea0dc7
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  *.rbc
3
+ *.swp
3
4
  .bundle
4
5
  .config
5
6
  .yardoc
data/.rubocop.yml CHANGED
@@ -1,8 +1,9 @@
1
- MethodLength:
2
- Max: 20
1
+ FileName:
2
+ Exclude:
3
+ - lib/lita-pagerduty.rb
3
4
 
4
- ClassLength:
5
- Max: 400
5
+ LineLength:
6
+ Max: 130
6
7
 
7
- Documentation:
8
+ AbcSize:
8
9
  Enabled: false
data/.travis.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.0
3
+ - 2.1
4
4
  script: bundle exec rake
5
5
  before_install:
6
6
  - gem update --system
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,9 @@
1
+ Pull requests are awesome! Pull requests with tests are even more awesome!
2
+
3
+ ## Quick steps
4
+
5
+ 1. Fork the repo.
6
+ 2. Run the tests: `bundle && rake`
7
+ 3. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, it needs a test!
8
+ 4. Make the test pass.
9
+ 5. Push to your fork and submit a pull request.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Eric Sigler
1
+ Copyright (c) 2014 PagerDuty
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # lita-pagerduty
2
2
 
3
- [![Build Status](https://travis-ci.org/esigler/lita-pagerduty.png?branch=master)](https://travis-ci.org/esigler/lita-pagerduty)
4
- [![Code Climate](https://codeclimate.com/github/esigler/lita-pagerduty.png)](https://codeclimate.com/github/esigler/lita-pagerduty)
5
- [![Coverage Status](https://coveralls.io/repos/esigler/lita-pagerduty/badge.png?branch=master)](https://coveralls.io/r/esigler/lita-pagerduty?branch=master)
3
+ [![Build Status](https://img.shields.io/travis/PagerDuty/lita-pagerduty/master.svg)](https://travis-ci.org/PagerDuty/lita-pagerduty)
4
+ [![MIT License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://tldrlegal.com/license/mit-license)
5
+ [![RubyGems :: RMuh Gem Version](http://img.shields.io/gem/v/lita-pagerduty.svg)](https://rubygems.org/gems/lita-pagerduty)
6
+ [![Coveralls Coverage](https://img.shields.io/coveralls/PagerDuty/lita-pagerduty/master.svg)](https://coveralls.io/r/PagerDuty/lita-pagerduty)
7
+ [![Code Climate](https://img.shields.io/codeclimate/github/PagerDuty/lita-pagerduty.svg)](https://codeclimate.com/github/PagerDuty/lita-pagerduty)
8
+ [![Gemnasium](https://img.shields.io/gemnasium/PagerDuty/lita-pagerduty.svg)](https://gemnasium.com/PagerDuty/lita-pagerduty)
6
9
 
7
- PagerDuty (http://pagerduty.com) handler for checking who's on call, scheduling, ack, resolve, etc.
10
+ A [PagerDuty](http://pagerduty.com) plugin for [Lita](https://github.com/jimmycuadra/lita).
8
11
 
9
12
  ## Installation
10
13
 
@@ -28,38 +31,38 @@ config.handlers.pagerduty.subdomain = ''
28
31
  ### Specific incidents
29
32
 
30
33
  ```
31
- Lita pager incidents all - Show all open incidents
32
- Lita pager incidents mine - Show all open incidents assigned to me
33
- Lita pager incident <incident ID> - Show a specific incident
34
+ pager incidents all - Show all open incidents
35
+ pager incidents mine - Show all open incidents assigned to me
36
+ pager incident <incident ID> - Show a specific incident
34
37
  ```
35
38
 
36
39
  ### Incident notes
37
40
 
38
41
  ```
39
- Lita pager notes <incident ID> - Show all notes for a specific incident
42
+ pager notes <incident ID> - Show all notes for a specific incident
40
43
  ```
41
44
 
42
45
  ### Acknowledging an incident
43
46
 
44
47
  ```
45
- Lita pager ack all - Acknowledge all triggered incidents
46
- Lita pager ack mine - Acknowledge all triggered incidents assigned to me
47
- Lita pager ack <incident ID> - Acknowledge a specific incident
48
+ pager ack all - Acknowledge all triggered incidents
49
+ pager ack mine - Acknowledge all triggered incidents assigned to me
50
+ pager ack <incident ID> - Acknowledge a specific incident
48
51
  ```
49
52
 
50
53
  ### Resolving an incident
51
54
 
52
55
  ```
53
- Lita pager resolve all - Resolve all triggered incidents
54
- Lita pager resolve mine - Resolve all triggered incidents assigned to me
55
- Lita pager resolve <incident ID> - Resolve a specific incident
56
+ pager resolve all - Resolve all triggered incidents
57
+ pager resolve mine - Resolve all triggered incidents assigned to me
58
+ pager resolve <incident ID> - Resolve a specific incident
56
59
  ```
57
60
 
58
61
  ### Misc
59
62
 
60
63
  ```
61
- Lita pager identify <email address> - Associate your chat user with your email address
62
- Lita pager forget - Remove your chat user / email association
64
+ pager identify <email address> - Associate your chat user with your email address
65
+ pager forget - Remove your chat user / email association
63
66
  ```
64
67
 
65
68
  ## License
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new(:rubocop)
5
7
 
6
- task default: :spec
8
+ task default: [:spec, :rubocop]
@@ -0,0 +1,73 @@
1
+ # Lita-related code
2
+ module Lita
3
+ # Plugin-related code
4
+ module Handlers
5
+ # Acknowledge-related routes
6
+ class PagerdutyAck < Handler
7
+ namespace 'Pagerduty'
8
+
9
+ include ::PagerdutyHelper::Incident
10
+ include ::PagerdutyHelper::Regex
11
+ include ::PagerdutyHelper::Utility
12
+
13
+ route(
14
+ /^pager\sack\sall$/,
15
+ :ack_all,
16
+ command: true,
17
+ help: {
18
+ t('help.ack_all.syntax') => t('help.ack_all.desc')
19
+ }
20
+ )
21
+
22
+ route(
23
+ /^pager\sack\smine$/,
24
+ :ack_mine,
25
+ command: true,
26
+ help: {
27
+ t('help.ack_mine.syntax') => t('help.ack_mine.desc')
28
+ }
29
+ )
30
+
31
+ route(
32
+ /^pager\sack\s#{INCIDENT_ID_PATTERN}$/,
33
+ :ack,
34
+ command: true,
35
+ help: {
36
+ t('help.ack.syntax') => t('help.ack.desc')
37
+ }
38
+ )
39
+
40
+ def ack_all(response)
41
+ incidents = fetch_all_incidents
42
+ return response.reply(t('incident.none')) unless incidents.count > 0
43
+ completed = []
44
+ incidents.each do |incident|
45
+ result = acknowledge_incident(incident.id)
46
+ completed.push(incident.id) if result == "#{incident.id}: Incident acknowledged"
47
+ response.reply(t('all.acknowledged', list: completed.join(', ')))
48
+ end
49
+ end
50
+
51
+ def ack_mine(response)
52
+ email = fetch_user(response.user)
53
+ return response.reply(t('identify.missing')) unless email
54
+ incidents = fetch_my_incidents(email)
55
+ return response.reply(t('incident.none_mine')) unless incidents.count > 0
56
+ completed = []
57
+ incidents.each do |incident|
58
+ result = acknowledge_incident(incident.id)
59
+ completed.push(incident.id) if result == "#{incident.id}: Incident acknowledged"
60
+ response.reply(t('all.acknowledged', list: completed.join(', ')))
61
+ end
62
+ end
63
+
64
+ def ack(response)
65
+ incident_id = response.match_data['incident_id']
66
+ return if incident_id == 'all' || incident_id == 'mine'
67
+ response.reply(acknowledge_incident(incident_id))
68
+ end
69
+ end
70
+
71
+ Lita.register_handler(PagerdutyAck)
72
+ end
73
+ end
@@ -0,0 +1,68 @@
1
+ # Lita-related code
2
+ module Lita
3
+ # Plugin-related code
4
+ module Handlers
5
+ # Incident-related routes
6
+ class PagerdutyIncident < Handler
7
+ namespace 'Pagerduty'
8
+
9
+ include ::PagerdutyHelper::Incident
10
+ include ::PagerdutyHelper::Regex
11
+ include ::PagerdutyHelper::Utility
12
+
13
+ route(
14
+ /^pager\sincidents\sall$/,
15
+ :incidents_all,
16
+ command: true,
17
+ help: {
18
+ t('help.incidents_all.syntax') => t('help.incidents_all.desc')
19
+ }
20
+ )
21
+
22
+ route(
23
+ /^pager\sincidents\smine$/,
24
+ :incidents_mine,
25
+ command: true,
26
+ help: {
27
+ t('help.incidents_mine.syntax') => t('help.incidents_mine.desc')
28
+ }
29
+ )
30
+
31
+ route(
32
+ /^pager\sincident\s#{INCIDENT_ID_PATTERN}$/,
33
+ :incident,
34
+ command: true,
35
+ help: {
36
+ t('help.incident.syntax') => t('help.incident.desc')
37
+ }
38
+ )
39
+
40
+ def incidents_all(response)
41
+ incidents = fetch_all_incidents
42
+ return response.reply(t('incident.none')) unless incidents.count > 0
43
+ incidents.each do |incident|
44
+ response.reply(format_incident(incident))
45
+ end
46
+ end
47
+
48
+ def incidents_mine(response)
49
+ email = fetch_user(response.user)
50
+ return response.reply(t('identify.missing')) unless email
51
+ incidents = fetch_my_incidents(email)
52
+ response.reply(t('incident.none_mine')) unless incidents.count > 0
53
+ incidents.each do |incident|
54
+ response.reply(format_incident(incident))
55
+ end
56
+ end
57
+
58
+ def incident(response)
59
+ incident_id = response.match_data['incident_id']
60
+ incident = fetch_incident(incident_id)
61
+ return response.reply(t('incident.not_found', id: incident_id)) if incident == 'No results'
62
+ response.reply(format_incident(incident))
63
+ end
64
+ end
65
+
66
+ Lita.register_handler(PagerdutyIncident)
67
+ end
68
+ end
@@ -0,0 +1,48 @@
1
+ # Lita-related code
2
+ module Lita
3
+ # Plugin-related code
4
+ module Handlers
5
+ # Note-related routes
6
+ class PagerdutyNote < Handler
7
+ namespace 'Pagerduty'
8
+
9
+ include ::PagerdutyHelper::Incident
10
+ include ::PagerdutyHelper::Regex
11
+ include ::PagerdutyHelper::Utility
12
+
13
+ route(
14
+ /^pager\snotes\s#{INCIDENT_ID_PATTERN}$/,
15
+ :notes,
16
+ command: true,
17
+ help: {
18
+ t('help.notes.syntax') => t('help.notes.desc')
19
+ }
20
+ )
21
+
22
+ route(
23
+ /^pager\snote\s#{INCIDENT_ID_PATTERN}\s(.+)$/,
24
+ :note,
25
+ command: true,
26
+ help: {
27
+ t('help.note.syntax') => t('help.note.desc')
28
+ }
29
+ )
30
+
31
+ def notes(response)
32
+ incident_id = response.match_data['incident_id']
33
+ incident = fetch_incident(incident_id)
34
+ return response.reply(t('incident.not_found', id: incident_id)) if incident == 'No results'
35
+ return response.reply("#{incident_id}: No notes") unless incident.notes.notes.count > 0
36
+ incident.notes.notes.each do |note|
37
+ response.reply(format_note(incident, note))
38
+ end
39
+ end
40
+
41
+ def note(response)
42
+ response.reply(t('error.not_implemented'))
43
+ end
44
+ end
45
+
46
+ Lita.register_handler(PagerdutyNote)
47
+ end
48
+ end
@@ -0,0 +1,73 @@
1
+ # Lita-related code
2
+ module Lita
3
+ # Plugin-related code
4
+ module Handlers
5
+ # Resolve-related routes
6
+ class PagerdutyResolve < Handler
7
+ namespace 'Pagerduty'
8
+
9
+ include ::PagerdutyHelper::Incident
10
+ include ::PagerdutyHelper::Regex
11
+ include ::PagerdutyHelper::Utility
12
+
13
+ route(
14
+ /^pager\sresolve\sall$/,
15
+ :resolve_all,
16
+ command: true,
17
+ help: {
18
+ t('help.resolve_all.syntax') => t('help.resolve_all.desc')
19
+ }
20
+ )
21
+
22
+ route(
23
+ /^pager\sresolve\smine$/,
24
+ :resolve_mine,
25
+ command: true,
26
+ help: {
27
+ t('help.resolve_mine.syntax') => t('help.resolve_mine.desc')
28
+ }
29
+ )
30
+
31
+ route(
32
+ /^pager\sresolve\s#{INCIDENT_ID_PATTERN}$/,
33
+ :resolve,
34
+ command: true,
35
+ help: {
36
+ t('help.resolve.syntax') => t('help.resolve.desc')
37
+ }
38
+ )
39
+
40
+ def resolve_all(response)
41
+ incidents = fetch_all_incidents
42
+ return response.reply(t('incident.none')) unless incidents.count > 0
43
+ completed = []
44
+ incidents.each do |incident|
45
+ result = resolve_incident(incident.id)
46
+ completed.push(incident.id) if result == "#{incident.id}: Incident resolved"
47
+ response.reply(t('all.resolved', list: completed.join(',')))
48
+ end
49
+ end
50
+
51
+ def resolve_mine(response)
52
+ email = fetch_user(response.user)
53
+ return response.reply(t('identify.missing')) unless email
54
+ incidents = fetch_my_incidents(email)
55
+ return response.reply(t('incident.none_mine')) unless incidents.count > 0
56
+ completed = []
57
+ incidents.each do |incident|
58
+ result = resolve_incident(incident.id)
59
+ completed.push(incident.id) if result == "#{incident.id}: Incident resolved"
60
+ response.reply(t('all.resolved', list: completed.join(',')))
61
+ end
62
+ end
63
+
64
+ def resolve(response)
65
+ incident_id = response.match_data['incident_id']
66
+ return if incident_id == 'all' || incident_id == 'mine'
67
+ response.reply(resolve_incident(incident_id))
68
+ end
69
+ end
70
+
71
+ Lita.register_handler(PagerdutyResolve)
72
+ end
73
+ end
@@ -0,0 +1,108 @@
1
+ require 'time'
2
+
3
+ # Lita-related code
4
+ module Lita
5
+ # Plugin-related code
6
+ module Handlers
7
+ # Utility-ish routes
8
+ class PagerdutyUtility < Handler
9
+ config :api_key, required: true
10
+ config :subdomain, required: true
11
+
12
+ namespace 'Pagerduty'
13
+
14
+ include ::PagerdutyHelper::Incident
15
+ include ::PagerdutyHelper::Regex
16
+ include ::PagerdutyHelper::Utility
17
+
18
+ route(
19
+ /^pager\soncall$/,
20
+ :on_call_list,
21
+ command: true,
22
+ help: {
23
+ t('help.on_call_list.syntax') => t('help.on_call_list.desc')
24
+ }
25
+ )
26
+
27
+ route(
28
+ /^pager\soncall\s(.*)$/,
29
+ :on_call_lookup,
30
+ command: true,
31
+ help: {
32
+ t('help.on_call_lookup.syntax') => t('help.on_call_lookup.desc')
33
+ }
34
+ )
35
+
36
+ route(
37
+ /^pager\sidentify\s#{EMAIL_PATTERN}$/,
38
+ :identify,
39
+ command: true,
40
+ help: {
41
+ t('help.identify.syntax') => t('help.identify.desc')
42
+ }
43
+ )
44
+
45
+ route(
46
+ /^pager\sforget$/,
47
+ :forget,
48
+ command: true,
49
+ help: {
50
+ t('help.forget.syntax') => t('help.forget.desc')
51
+ }
52
+ )
53
+
54
+ def on_call_list(response)
55
+ schedules = pd_client.get_schedules.schedules
56
+ if schedules.any?
57
+ schedule_list = schedules.map(&:name).join(', ')
58
+ response.reply(t('on_call_list.response', schedules: schedule_list))
59
+ else
60
+ response.reply(t('on_call_list.no_schedules_found'))
61
+ end
62
+ end
63
+
64
+ def on_call_lookup(response)
65
+ schedule_name = response.match_data[1].strip
66
+ schedule = pd_client.get_schedules.schedules.find { |s| s.name == schedule_name }
67
+
68
+ unless schedule
69
+ return response.reply(t('on_call_lookup.no_matching_schedule', schedule_name: schedule_name))
70
+ end
71
+
72
+ if (user = lookup_on_call_user(schedule.id))
73
+ response.reply(t('on_call_lookup.response', name: user.name, email: user.email, schedule_name: schedule_name))
74
+ else
75
+ response.reply(t('on_call_lookup.no_one_on_call', schedule_name: schedule_name))
76
+ end
77
+ end
78
+
79
+ def identify(response)
80
+ email = response.match_data['email']
81
+ stored_email = fetch_user(response.user)
82
+ return response.reply(t('identify.already')) if stored_email
83
+ store_user(response.user, email)
84
+ response.reply(t('identify.complete'))
85
+ end
86
+
87
+ def forget(response)
88
+ stored_email = fetch_user(response.user)
89
+ return response.reply(t('forget.unknown')) unless stored_email
90
+ delete_user(response.user)
91
+ response.reply(t('forget.complete'))
92
+ end
93
+
94
+ private
95
+
96
+ def lookup_on_call_user(schedule_id)
97
+ now = Time.now.utc
98
+ pd_client.get_schedule_users(
99
+ id: schedule_id,
100
+ since: now.iso8601,
101
+ until: (now + 3600).iso8601
102
+ ).first
103
+ end
104
+ end
105
+
106
+ Lita.register_handler(PagerdutyUtility)
107
+ end
108
+ end
@@ -1 +1,17 @@
1
- require 'lita/handlers/pagerduty'
1
+ require 'lita'
2
+
3
+ Lita.load_locales Dir[File.expand_path(
4
+ File.join('..', '..', 'locales', '*.yml'), __FILE__
5
+ )]
6
+
7
+ require 'pagerduty'
8
+
9
+ require 'pagerduty_helper/incident'
10
+ require 'pagerduty_helper/regex'
11
+ require 'pagerduty_helper/utility'
12
+
13
+ require 'lita/handlers/pagerduty_ack'
14
+ require 'lita/handlers/pagerduty_incident'
15
+ require 'lita/handlers/pagerduty_note'
16
+ require 'lita/handlers/pagerduty_resolve'
17
+ require 'lita/handlers/pagerduty_utility'
@@ -0,0 +1,61 @@
1
+ # Helper Code for PagerDuty Lita Handler
2
+ module PagerdutyHelper
3
+ # Incident-related functions
4
+ module Incident
5
+ def format_incident(incident)
6
+ t('incident.info', id: incident.id,
7
+ subject: incident.trigger_summary_data.subject,
8
+ assigned: incident.assigned_to_user.email)
9
+ end
10
+
11
+ def resolve_incident(incident_id)
12
+ incident = fetch_incident(incident_id)
13
+ return t('incident.not_found', id: incident_id) if incident == 'No results'
14
+ return t('incident.already_set', id: incident_id, status: incident.status) if incident.status == 'resolved'
15
+ results = incident.resolve
16
+ if results.key?('status') && results['status'] == 'resolved'
17
+ t('incident.resolved', id: incident_id)
18
+ else
19
+ t('incident.unable_to_resolve', id: incident_id)
20
+ end
21
+ end
22
+
23
+ def fetch_all_incidents
24
+ client = pd_client
25
+ list = []
26
+ # FIXME: Workaround on current PD Gem
27
+ client.incidents.incidents.each do |incident|
28
+ list.push(incident) if incident.status != 'resolved'
29
+ end
30
+ list
31
+ end
32
+
33
+ def fetch_my_incidents(email)
34
+ # FIXME: Workaround
35
+ incidents = fetch_all_incidents
36
+ list = []
37
+ incidents.each do |incident|
38
+ list.push(incident) if incident.assigned_to_user.email == email
39
+ end
40
+ list
41
+ end
42
+
43
+ def fetch_incident(incident_id)
44
+ client = pd_client
45
+ client.get_incident(id: incident_id)
46
+ end
47
+
48
+ def acknowledge_incident(incident_id)
49
+ incident = fetch_incident(incident_id)
50
+ return t('incident.not_found', id: incident_id) if incident == 'No results'
51
+ return t('incident.already_set', id: incident_id, status: incident.status) if incident.status == 'acknowledged'
52
+ return t('incident.already_set', id: incident_id, status: incident.status) if incident.status == 'resolved'
53
+ results = incident.acknowledge
54
+ if results.key?('status') && results['status'] == 'acknowledged'
55
+ t('incident.acknowledged', id: incident_id)
56
+ else
57
+ t('incident.unable_to_acknowledge', id: incident_id)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,8 @@
1
+ # Helper Code for PagerDuty Lita Handler
2
+ module PagerdutyHelper
3
+ # Utility functions
4
+ module Regex
5
+ INCIDENT_ID_PATTERN = /(?<incident_id>[a-zA-Z0-9+]{1,6})/
6
+ EMAIL_PATTERN = /(?<email>[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+)/i
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ # Helper Code for PagerDuty Lita Handler
2
+ module PagerdutyHelper
3
+ # Utility functions
4
+ module Utility
5
+ def pd_client
6
+ ::Pagerduty.new(token: config.api_key, subdomain: config.subdomain)
7
+ end
8
+
9
+ def format_note(incident, note)
10
+ t('note.show', id: incident.id, content: note.content, email: note.user.email)
11
+ end
12
+
13
+ def store_user(user, email)
14
+ redis.set(format_user(user), email)
15
+ end
16
+
17
+ def fetch_user(user)
18
+ redis.get(format_user(user))
19
+ end
20
+
21
+ def delete_user(user)
22
+ redis.del(format_user(user))
23
+ end
24
+
25
+ def format_user(user)
26
+ "email_#{user.id}"
27
+ end
28
+ end
29
+ end