jiraSOAP 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.yardopts +2 -3
- data/ChangeLog +15 -0
- data/LICENSE.txt +1 -1
- data/README.markdown +51 -41
- data/Rakefile +57 -0
- data/docs/GettingStarted.markdown +36 -0
- data/lib/jiraSOAP.rb +7 -4
- data/lib/jiraSOAP/api.rb +59 -53
- data/lib/jiraSOAP/api/additions.rb +4 -6
- data/lib/jiraSOAP/api/attachments.rb +18 -8
- data/lib/jiraSOAP/api/avatars.rb +30 -17
- data/lib/jiraSOAP/api/comments.rb +16 -11
- data/lib/jiraSOAP/api/filters.rb +13 -10
- data/lib/jiraSOAP/api/issue_data_types.rb +29 -21
- data/lib/jiraSOAP/api/issues.rb +46 -31
- data/lib/jiraSOAP/api/project_roles.rb +22 -15
- data/lib/jiraSOAP/api/projects.rb +33 -20
- data/lib/jiraSOAP/api/schemes.rb +9 -9
- data/lib/jiraSOAP/api/server_info.rb +11 -9
- data/lib/jiraSOAP/api/users.rb +58 -10
- data/lib/jiraSOAP/api/versions.rb +15 -11
- data/lib/jiraSOAP/api/worklog.rb +14 -0
- data/lib/jiraSOAP/core_extensions.rb +8 -0
- data/lib/jiraSOAP/entities.rb +3 -0
- data/lib/jiraSOAP/entities/attachment_metadata.rb +28 -9
- data/lib/jiraSOAP/entities/avatar.rb +29 -10
- data/lib/jiraSOAP/entities/comment.rb +37 -11
- data/lib/jiraSOAP/entities/component.rb +1 -1
- data/lib/jiraSOAP/entities/custom_field_value.rb +17 -12
- data/lib/jiraSOAP/entities/described_entity.rb +9 -5
- data/lib/jiraSOAP/entities/dynamic_entity.rb +12 -5
- data/lib/jiraSOAP/entities/entity.rb +33 -27
- data/lib/jiraSOAP/entities/field.rb +1 -1
- data/lib/jiraSOAP/entities/field_value.rb +16 -6
- data/lib/jiraSOAP/entities/filter.rb +18 -5
- data/lib/jiraSOAP/entities/issue.rb +74 -29
- data/lib/jiraSOAP/entities/issue_property.rb +9 -6
- data/lib/jiraSOAP/entities/issue_security_scheme.rb +1 -1
- data/lib/jiraSOAP/entities/issue_type.rb +9 -4
- data/lib/jiraSOAP/entities/named_entity.rb +8 -4
- data/lib/jiraSOAP/entities/notification_scheme.rb +1 -1
- data/lib/jiraSOAP/entities/permission.rb +14 -6
- data/lib/jiraSOAP/entities/permission_mapping.rb +9 -5
- data/lib/jiraSOAP/entities/permission_scheme.rb +7 -4
- data/lib/jiraSOAP/entities/priority.rb +7 -4
- data/lib/jiraSOAP/entities/project.rb +29 -13
- data/lib/jiraSOAP/entities/project_role.rb +3 -2
- data/lib/jiraSOAP/entities/resolution.rb +1 -1
- data/lib/jiraSOAP/entities/scheme.rb +5 -1
- data/lib/jiraSOAP/entities/server_configuration.rb +39 -14
- data/lib/jiraSOAP/entities/server_info.rb +20 -8
- data/lib/jiraSOAP/entities/status.rb +1 -1
- data/lib/jiraSOAP/entities/time_info.rb +12 -5
- data/lib/jiraSOAP/entities/user.rb +8 -4
- data/lib/jiraSOAP/entities/usergroup.rb +15 -0
- data/lib/jiraSOAP/entities/username.rb +7 -1
- data/lib/jiraSOAP/entities/version.rb +20 -12
- data/lib/jiraSOAP/entities/worklog.rb +28 -0
- data/lib/jiraSOAP/handsoap_extensions.rb +31 -80
- data/lib/jiraSOAP/{JIRAservice.rb → jira_service.rb} +19 -14
- data/lib/jiraSOAP/{macruby_bonuses.rb → macruby_extensions.rb} +5 -14
- data/lib/jiraSOAP/nokogiri_extensions.rb +68 -0
- data/lib/jiraSOAP/url.rb +10 -2
- data/lib/jiraSOAP/version.rb +3 -0
- metadata +29 -55
- data/yard-jiraSOAP.rb +0 -65
@@ -1,49 +1,56 @@
|
|
1
|
-
module JIRA
|
2
|
-
|
3
|
-
# @group
|
1
|
+
module JIRA::RemoteAPI
|
2
|
+
|
3
|
+
# @group Project Roles
|
4
4
|
|
5
5
|
# @return [Array<JIRA::ProjectRole>]
|
6
|
-
def
|
7
|
-
|
6
|
+
def project_roles
|
7
|
+
array_jira_call JIRA::ProjectRole, 'getProjectRoles'
|
8
8
|
end
|
9
|
+
alias_method :get_project_roles, :project_roles
|
9
10
|
|
10
11
|
# @param [String] role_id
|
11
12
|
# @return [JIRA::ProjectRole]
|
12
|
-
def
|
13
|
-
JIRA::ProjectRole.new_with_xml
|
13
|
+
def project_role_with_id role_id
|
14
|
+
JIRA::ProjectRole.new_with_xml jira_call( 'getProjectRole', role_id )
|
14
15
|
end
|
16
|
+
alias_method :get_project_role_with_id, :project_role_with_id
|
15
17
|
|
16
18
|
# @param [JIRA::ProjectRole] project_role
|
17
19
|
# @return [JIRA::ProjectRole] the role that was created
|
18
20
|
def create_project_role_with_role project_role
|
19
|
-
JIRA::ProjectRole.new_with_xml
|
21
|
+
JIRA::ProjectRole.new_with_xml jira_call( 'createProjectRole', project_role )
|
20
22
|
end
|
21
23
|
|
24
|
+
##
|
22
25
|
# @note JIRA 4.0 and 4.2 returns an exception if the name already exists
|
26
|
+
#
|
23
27
|
# Returns true if the name does not exist.
|
28
|
+
#
|
24
29
|
# @param [String] project_role_name
|
25
30
|
# @return [Boolean] true if successful
|
26
31
|
def project_role_name_unique? project_role_name
|
27
|
-
|
32
|
+
jira_call( 'isProjectRoleNameUnique', project_role_name ).to_boolean
|
28
33
|
end
|
29
34
|
|
30
|
-
|
35
|
+
##
|
36
|
+
# @note The confirm argument appears to do nothing (at least on JIRA 4.0)
|
37
|
+
#
|
31
38
|
# @param [JIRA::ProjectRole] project_role
|
32
39
|
# @param [Boolean] confirm
|
33
40
|
# @return [Boolean] true if successful
|
34
41
|
def delete_project_role project_role, confirm = true
|
35
|
-
|
42
|
+
jira_call 'deleteProjectRole', project_role, confirm
|
36
43
|
true
|
37
44
|
end
|
38
45
|
|
46
|
+
##
|
39
47
|
# @note JIRA 4.0 will not update project roles, it will instead throw
|
40
|
-
#
|
48
|
+
# an exception telling you that the project role already exists
|
49
|
+
#
|
41
50
|
# @param [JIRA::ProjectRole] project_role
|
42
51
|
# @return [JIRA::ProjectRole] the role after the update
|
43
52
|
def update_project_role_with_role project_role
|
44
|
-
JIRA::ProjectRole.new_with_xml
|
53
|
+
JIRA::ProjectRole.new_with_xml jira_call( 'updateProjectRole', project_role )
|
45
54
|
end
|
46
55
|
|
47
|
-
# @endgroup
|
48
|
-
end
|
49
56
|
end
|
@@ -1,67 +1,80 @@
|
|
1
|
-
module JIRA
|
2
|
-
module RemoteAPI
|
3
|
-
# @group Working with Projects
|
1
|
+
module JIRA::RemoteAPI
|
4
2
|
|
3
|
+
# @group Projects
|
4
|
+
|
5
|
+
##
|
5
6
|
# You need to explicitly ask for schemes in order to get them. By
|
6
7
|
# default, most project fetching methods purposely leave out all
|
7
8
|
# the scheme information as permission schemes can be very large.
|
9
|
+
#
|
8
10
|
# @param [String] project_key
|
9
11
|
# @return [JIRA::Project]
|
10
|
-
def
|
11
|
-
JIRA::Project.new_with_xml
|
12
|
+
def project_with_key project_key
|
13
|
+
JIRA::Project.new_with_xml jira_call( 'getProjectByKey', project_key )
|
12
14
|
end
|
15
|
+
alias_method :get_project_with_key, :project_with_key
|
13
16
|
|
17
|
+
##
|
14
18
|
# Requires you to set at least a project name, key, and lead.
|
15
19
|
# However, it is also a good idea to set other project properties, such as
|
16
20
|
# the permission scheme as the default permission scheme can be too
|
17
21
|
# restrictive in most cases.
|
22
|
+
#
|
18
23
|
# @param [JIRA::Project] project
|
19
24
|
# @return [JIRA::Project]
|
20
25
|
def create_project_with_project project
|
21
|
-
JIRA::Project.new_with_xml
|
26
|
+
JIRA::Project.new_with_xml jira_call( 'createProjectFromObject', project )
|
22
27
|
end
|
23
28
|
|
29
|
+
##
|
24
30
|
# The id of the project is the only field that you cannot update. Or, at
|
25
31
|
# least the only field I know that you cannot update.
|
32
|
+
#
|
26
33
|
# @param [JIRA::Project] project
|
27
34
|
# @return [JIRA::Project]
|
28
35
|
def update_project_with_project project
|
29
|
-
JIRA::Project.new_with_xml
|
36
|
+
JIRA::Project.new_with_xml jira_call( 'updateProject', project )
|
30
37
|
end
|
31
38
|
|
32
39
|
# @param [String] project_id
|
33
40
|
# @return [JIRA::Project]
|
34
|
-
def
|
35
|
-
JIRA::Project.new_with_xml
|
41
|
+
def project_with_id project_id
|
42
|
+
JIRA::Project.new_with_xml jira_call( 'getProjectById', project_id )
|
36
43
|
end
|
44
|
+
alias_method :get_project_with_id, :project_with_id
|
37
45
|
|
38
|
-
|
46
|
+
##
|
47
|
+
# @todo Parse the permission scheme
|
39
48
|
# @note This method does not yet include the permission scheme.
|
49
|
+
#
|
40
50
|
# @param [String] project_id
|
41
51
|
# @return [JIRA::Project]
|
42
|
-
def
|
43
|
-
JIRA::Project.new_with_xml
|
52
|
+
def project_including_schemes_with_id project_id
|
53
|
+
JIRA::Project.new_with_xml jira_call( 'getProjectWithSchemesById', project_id )
|
44
54
|
end
|
55
|
+
alias_method :get_project_including_schemes_with_id, :project_including_schemes_with_id
|
45
56
|
|
46
57
|
# @param [String] project_name
|
47
58
|
# @return [Array<JIRA::IssueType>]
|
48
|
-
def
|
49
|
-
|
59
|
+
def issue_types_for_project_with_id project_id
|
60
|
+
array_jira_call JIRA::IssueType, 'getIssueTypesForProject', project_id
|
50
61
|
end
|
62
|
+
alias_method :get_issue_types_for_project_with_id, :issue_types_for_project_with_id
|
51
63
|
|
52
|
-
|
64
|
+
##
|
65
|
+
# @note This will not fill in {JIRA::Scheme} data for the projects.
|
66
|
+
#
|
53
67
|
# @return [Array<JIRA::Project>]
|
54
|
-
def
|
55
|
-
|
68
|
+
def projects_without_schemes
|
69
|
+
array_jira_call JIRA::Project, 'getProjectsNoSchemes'
|
56
70
|
end
|
71
|
+
alias_method :get_projects_without_schemes, :projects_without_schemes
|
57
72
|
|
58
73
|
# @param [String] project_key
|
59
74
|
# @return [Boolean] true if successful
|
60
75
|
def delete_project_with_key project_key
|
61
|
-
|
76
|
+
jira_call 'deleteProject', project_key
|
62
77
|
true
|
63
78
|
end
|
64
79
|
|
65
|
-
# @endgroup
|
66
|
-
end
|
67
80
|
end
|
data/lib/jiraSOAP/api/schemes.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
module JIRA
|
2
|
-
|
3
|
-
# @group
|
1
|
+
module JIRA::RemoteAPI
|
2
|
+
|
3
|
+
# @group Schemes
|
4
4
|
|
5
5
|
# @return [Array<JIRA::NotificationScheme>]
|
6
|
-
def
|
7
|
-
|
6
|
+
def notification_schemes
|
7
|
+
array_jira_call JIRA::NotificationScheme, 'getNotificationSchemes'
|
8
8
|
end
|
9
|
+
alias_method :get_notification_schemes, :notification_schemes
|
9
10
|
|
10
11
|
# @return [Array<JIRA::PermissionScheme>]
|
11
|
-
def
|
12
|
-
|
12
|
+
def permission_schemes
|
13
|
+
array_jira_call JIRA::PermissionScheme, 'getPermissionSchemes'
|
13
14
|
end
|
15
|
+
alias_method :get_permission_schemes, :permission_schemes
|
14
16
|
|
15
|
-
# @endgroup
|
16
|
-
end
|
17
17
|
end
|
@@ -1,18 +1,20 @@
|
|
1
|
-
module JIRA
|
2
|
-
module RemoteAPI
|
3
|
-
# @group Getting information about the server
|
1
|
+
module JIRA::RemoteAPI
|
4
2
|
|
3
|
+
# @group Server Information
|
4
|
+
|
5
|
+
##
|
5
6
|
# The @build_date attribute is a Time value, but does not include a time.
|
7
|
+
#
|
6
8
|
# @return [JIRA::ServerInfo]
|
7
|
-
def
|
8
|
-
JIRA::ServerInfo.new_with_xml
|
9
|
+
def server_info
|
10
|
+
JIRA::ServerInfo.new_with_xml jira_call( 'getServerInfo' )
|
9
11
|
end
|
12
|
+
alias_method :get_server_info, :server_info
|
10
13
|
|
11
14
|
# @return [JIRA::ServerConfiguration]
|
12
|
-
def
|
13
|
-
JIRA::ServerConfiguration.new_with_xml
|
15
|
+
def server_configuration
|
16
|
+
JIRA::ServerConfiguration.new_with_xml jira_call( 'getConfiguration' )
|
14
17
|
end
|
18
|
+
alias_method :get_server_configuration, :server_configuration
|
15
19
|
|
16
|
-
# @endgroup
|
17
|
-
end
|
18
20
|
end
|
data/lib/jiraSOAP/api/users.rb
CHANGED
@@ -1,35 +1,83 @@
|
|
1
|
-
module JIRA
|
2
|
-
|
3
|
-
# @group
|
1
|
+
module JIRA::RemoteAPI
|
2
|
+
|
3
|
+
# @group Users
|
4
4
|
|
5
5
|
# @param [String] user_name
|
6
6
|
# @return [JIRA::User]
|
7
|
-
def
|
8
|
-
JIRA::User.new_with_xml
|
7
|
+
def user_with_name user_name
|
8
|
+
JIRA::User.new_with_xml jira_call( 'getUser', user_name )
|
9
9
|
end
|
10
|
+
alias_method :get_user_with_name, :user_with_name
|
10
11
|
|
12
|
+
##
|
11
13
|
# It seems that creating a user without any permission groups will trigger
|
12
14
|
# an exception on some versions of JIRA. The irony is that this method provides
|
13
15
|
# no way to add groups. The good news though, is that the creation will still
|
14
16
|
# happen; but the user will have no permissions.
|
17
|
+
#
|
15
18
|
# @param [String] username
|
16
19
|
# @param [String] password
|
17
20
|
# @param [String] full_name
|
18
21
|
# @param [String] email
|
19
22
|
# @return [JIRA::User,nil] depending on your JIRA version, this method may
|
20
|
-
#
|
23
|
+
# always raise an exception instead of actually returning anything
|
21
24
|
def create_user username, password, full_name, email
|
22
|
-
fragment =
|
25
|
+
fragment = jira_call( 'createUser', username, password, full_name, email )
|
23
26
|
JIRA::User.new_with_xml fragment
|
24
27
|
end
|
25
28
|
|
26
29
|
# @param [String] username
|
27
30
|
# @return [Boolean] true if successful
|
28
31
|
def delete_user_with_name username
|
29
|
-
|
32
|
+
jira_call 'deleteUser', username
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param [String] group_name
|
37
|
+
# @return [JIRA::UserGroup]
|
38
|
+
def group_with_name group_name
|
39
|
+
frag = jira_call 'getGroup', group_name
|
40
|
+
JIRA::UserGroup.new_with_xml frag
|
41
|
+
end
|
42
|
+
alias_method :get_group_with_name, :group_with_name
|
43
|
+
|
44
|
+
# @param [JIRA::UserGroup] group
|
45
|
+
# @param [JIRA::User] user
|
46
|
+
# @return [Boolean] true if successful
|
47
|
+
def add_user_to_group group, user
|
48
|
+
jira_call 'addUserToGroup', group, user
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param [JIRA::UserGroup] group
|
53
|
+
# @param [JIRA::User] user
|
54
|
+
# @return [Boolean]
|
55
|
+
def remove_user_from_group group, user
|
56
|
+
jira_call 'removeUserFromGroup', group, user
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Create a new user group. You can initialize the group
|
62
|
+
# with a user if you wish.
|
63
|
+
#
|
64
|
+
# @param [String] group_name
|
65
|
+
# @param [JIRA::User] user
|
66
|
+
# @return [JIRA::UserGroup]
|
67
|
+
def create_user_group group_name, user = nil
|
68
|
+
frag = jira_call 'createGroup', group_name, user
|
69
|
+
JIRA::UserGroup.new_with_xml frag
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# @todo Find out the semantics of swap_group
|
74
|
+
#
|
75
|
+
# @param [String] group_name
|
76
|
+
# @param [String] swap_group
|
77
|
+
# @return [Boolean] true if successful
|
78
|
+
def delete_user_group group_name, swap_group
|
79
|
+
jira_call 'deleteGroup', group_name, swap_group
|
30
80
|
true
|
31
81
|
end
|
32
82
|
|
33
|
-
# @endgroup
|
34
|
-
end
|
35
83
|
end
|
@@ -1,13 +1,15 @@
|
|
1
|
-
module JIRA
|
2
|
-
|
3
|
-
# @group
|
1
|
+
module JIRA::RemoteAPI
|
2
|
+
|
3
|
+
# @group Versions
|
4
4
|
|
5
5
|
# @param [String] project_key
|
6
6
|
# @return [Array<JIRA::Version>]
|
7
|
-
def
|
8
|
-
|
7
|
+
def versions_for_project project_key
|
8
|
+
array_jira_call JIRA::Version, 'getVersions', project_key
|
9
9
|
end
|
10
|
+
alias_method :get_versions_for_project, :versions_for_project
|
10
11
|
|
12
|
+
##
|
11
13
|
# New versions cannot have the archived bit set and the release date
|
12
14
|
# field will ignore the time of day you give it and instead insert
|
13
15
|
# the time zone offset as the time of day.
|
@@ -17,34 +19,36 @@ module RemoteAPI
|
|
17
19
|
#
|
18
20
|
# Descriptions do not appear to be included with JIRA::Version objects
|
19
21
|
# that SOAP API provides.
|
22
|
+
#
|
20
23
|
# @param [String] project_key
|
21
24
|
# @param [JIRA::Version] version
|
22
25
|
# @return [JIRA::Version]
|
23
26
|
def add_version_to_project_with_key project_key, version
|
24
|
-
JIRA::Version.new_with_xml
|
27
|
+
JIRA::Version.new_with_xml jira_call( 'addVersion', project_key, version )
|
25
28
|
end
|
26
29
|
|
30
|
+
##
|
27
31
|
# The archive state can only be set to true for versions that have not been
|
28
32
|
# released. However, this is not reflected by the return value of this method.
|
33
|
+
#
|
29
34
|
# @param [String] project_key
|
30
35
|
# @param [String] version_name
|
31
36
|
# @param [Boolean] state
|
32
37
|
# @return [Boolean] true if successful
|
33
38
|
def set_archive_state_for_version_for_project project_key, version_name, state
|
34
|
-
|
39
|
+
jira_call 'archiveVersion', project_key, version_name, state
|
35
40
|
true
|
36
41
|
end
|
37
42
|
|
43
|
+
##
|
38
44
|
# You can set the release state for a project with this method.
|
45
|
+
#
|
39
46
|
# @param [String] project_name
|
40
47
|
# @param [JIRA::Version] version
|
41
48
|
# @return [Boolean] true if successful
|
42
49
|
def release_state_for_version_for_project project_name, version
|
43
|
-
|
50
|
+
jira_call 'releaseVersion', project_name, version
|
44
51
|
true
|
45
52
|
end
|
46
53
|
|
47
|
-
# @endgroup
|
48
|
-
end
|
49
54
|
end
|
50
|
-
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module JIRA::RemoteAPI
|
2
|
+
|
3
|
+
# @group Worklogs
|
4
|
+
|
5
|
+
##
|
6
|
+
# Adds a worklog to the given issue.
|
7
|
+
#
|
8
|
+
# @param [String] issue_key
|
9
|
+
# @param [JIRA::Worklog] worklog
|
10
|
+
def add_worklog_and_auto_adjust_remaining_estimate issue_key, worklog
|
11
|
+
JIRA::Worklog.new_with_xml call( 'addWorklogAndAutoAdjustRemainingEstimate', issue_key, worklog ).first
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/lib/jiraSOAP/entities.rb
CHANGED
@@ -10,6 +10,7 @@ require 'jiraSOAP/entities/project_role'
|
|
10
10
|
|
11
11
|
require 'jiraSOAP/entities/username'
|
12
12
|
require 'jiraSOAP/entities/user'
|
13
|
+
require 'jiraSOAP/entities/usergroup'
|
13
14
|
|
14
15
|
require 'jiraSOAP/entities/field_value'
|
15
16
|
require 'jiraSOAP/entities/custom_field_value'
|
@@ -38,3 +39,5 @@ require 'jiraSOAP/entities/issue'
|
|
38
39
|
require 'jiraSOAP/entities/time_info'
|
39
40
|
require 'jiraSOAP/entities/server_info'
|
40
41
|
require 'jiraSOAP/entities/server_configuration'
|
42
|
+
|
43
|
+
require 'jiraSOAP/entities/worklog'
|
@@ -1,14 +1,33 @@
|
|
1
|
-
|
1
|
+
##
|
2
2
|
# Only contains the metadata for an attachment. The URI for an attachment
|
3
3
|
# appears to be of the form
|
4
4
|
# "{JIRA::JIRAService.endpoint_url}/secure/attachment/{#id}/{#file_name}"
|
5
5
|
class JIRA::AttachmentMetadata < JIRA::NamedEntity
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
|
7
|
+
# @return [String]
|
8
|
+
add_attribute :author, 'author', :content
|
9
|
+
|
10
|
+
# @return [String]
|
11
|
+
add_attribute :file_name, 'filename', :content
|
12
|
+
alias_method :filename, :file_name
|
13
|
+
|
14
|
+
# @return [String]
|
15
|
+
add_attribute :mime_type, 'mimetype', :content
|
16
|
+
alias_method :content_type, :mime_type
|
17
|
+
|
18
|
+
##
|
19
|
+
# Measured in bytes
|
20
|
+
#
|
21
|
+
# @return [Number]
|
22
|
+
add_attribute :file_size, 'filesize', :to_i
|
23
|
+
|
24
|
+
# @return [Time]
|
25
|
+
add_attribute :create_time, 'created', :to_iso_date
|
26
|
+
|
27
|
+
##
|
28
|
+
# Fetch the attachment from the server.
|
29
|
+
def attachment
|
30
|
+
raise NotImplementedError, 'Please implement me. :('
|
31
|
+
end
|
32
|
+
|
14
33
|
end
|