ketchup 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENCE +20 -0
- data/README.textile +123 -0
- data/lib/ketchup.rb +36 -0
- data/lib/ketchup/api.rb +80 -0
- data/lib/ketchup/item.rb +75 -0
- data/lib/ketchup/item_array.rb +85 -0
- data/lib/ketchup/meeting.rb +96 -0
- data/lib/ketchup/meeting_array.rb +92 -0
- data/lib/ketchup/note.rb +73 -0
- data/lib/ketchup/note_array.rb +85 -0
- data/lib/ketchup/profile.rb +125 -0
- data/lib/ketchup/project.rb +51 -0
- data/spec/ketchup/api_spec.rb +120 -0
- data/spec/ketchup/item_array_spec.rb +125 -0
- data/spec/ketchup/item_spec.rb +127 -0
- data/spec/ketchup/meeting_array_spec.rb +141 -0
- data/spec/ketchup/meeting_spec.rb +142 -0
- data/spec/ketchup/note_array_spec.rb +125 -0
- data/spec/ketchup/note_spec.rb +126 -0
- data/spec/ketchup/profile_spec.rb +148 -0
- data/spec/ketchup/project_spec.rb +75 -0
- data/spec/ketchup_spec.rb +20 -0
- data/spec/spec_helper.rb +30 -0
- metadata +116 -0
data/LICENCE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Paul Campbell, Pat Allan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
h1. Ketchup
|
2
|
+
|
3
|
+
This is the official Ruby interface to the API for "Ketchup":http://www.useketchup.com: A place for all your meeting notes.
|
4
|
+
|
5
|
+
h2. Installation
|
6
|
+
|
7
|
+
<pre><code>gem install ketchup</code></pre>
|
8
|
+
|
9
|
+
h2. Usage
|
10
|
+
|
11
|
+
Everything in Ketchup comes down to the user you're logged in as, and this library reflects that - you create a new connection and manage everything through a profile object:
|
12
|
+
|
13
|
+
<pre><code>profile = Ketchup.authenticate('user@domain.com', 'password')</code></pre>
|
14
|
+
|
15
|
+
None of the usage is particularly complex, but if you're confused with any of the notes below, either read "the documentation":http://rdoc.info/projects/hypertiny/ketchup or "the sauce":http://github.com/hypertiny/ketchup.
|
16
|
+
|
17
|
+
h3. Meetings
|
18
|
+
|
19
|
+
A profile object provides access to all your meetings simply enough:
|
20
|
+
|
21
|
+
<pre><code>profile.meetings.each do |meeting|
|
22
|
+
puts meeting.title
|
23
|
+
end
|
24
|
+
meeting = profile.meetings.create 'title' => 'Important Discussion'
|
25
|
+
meeting.title = 'Nothing Important'
|
26
|
+
meeting.save</code></pre>
|
27
|
+
|
28
|
+
All of a meeting's details are accesible through these meeting objects.
|
29
|
+
|
30
|
+
<pre><code>meeting.location #=> 'Abbey Road'
|
31
|
+
meeting.attendees #=> 'John, Paul, George and Ringo'</code></pre>
|
32
|
+
|
33
|
+
Meeting dates are parsed from natural language, just like in Ketchup's web interface.
|
34
|
+
|
35
|
+
<pre><code>meeting.date = 'Tomorrow at 4pm'</code></pre>
|
36
|
+
|
37
|
+
You can also filter meetings by the same categories as the web interface:
|
38
|
+
|
39
|
+
<pre><code>profile.meetings.today
|
40
|
+
profile.meetings.upcoming
|
41
|
+
profile.meetings.previous</code></pre>
|
42
|
+
|
43
|
+
h3. Items
|
44
|
+
|
45
|
+
Agenda items can be manipulated for each meeting. They're pretty slim objects through - the only editable attribute is their content.
|
46
|
+
|
47
|
+
<pre><code>meeting.items.each do |item|
|
48
|
+
puts item.content
|
49
|
+
end
|
50
|
+
item = meeting.items.build 'content' => 'What are we talking about?'
|
51
|
+
item.content = 'Minutes from Last Meeting'
|
52
|
+
item.save</code></pre>
|
53
|
+
|
54
|
+
You can also re-order a full set of items for a given meeting:
|
55
|
+
|
56
|
+
<pre><code>meeting.items.reorder item_b, item_c, item_a</code></pre>
|
57
|
+
|
58
|
+
h3. Notes
|
59
|
+
|
60
|
+
Notes are the bullet points under each item, and behave in much the same way. Also, the only piece of information that they have of any interest is the content attribute.
|
61
|
+
|
62
|
+
<pre><code>item.notes.each do |note|
|
63
|
+
puts note.content
|
64
|
+
end
|
65
|
+
note = item.notes.create 'content' => 'Are we done yet?'
|
66
|
+
note.content = 'Next meeting will be shorter'
|
67
|
+
note.save</code></pre>
|
68
|
+
|
69
|
+
Just like with items, you can re-order a full set of notes:
|
70
|
+
|
71
|
+
<pre><code>item.notes.reorder note_b, note_c, note_a</code></pre>
|
72
|
+
|
73
|
+
h3. Projects
|
74
|
+
|
75
|
+
Projects are implicitly created through meetings:
|
76
|
+
|
77
|
+
<pre><code>profile.meetings.create(
|
78
|
+
'title' => 'Monday',
|
79
|
+
'project_name' => 'Stand ups'
|
80
|
+
)</code></pre>
|
81
|
+
|
82
|
+
You can access these projects through the profile object, and the meetings that are in each of them:
|
83
|
+
|
84
|
+
<pre><code>profile.projects.each do |project|
|
85
|
+
puts project.name
|
86
|
+
end
|
87
|
+
project = profiles.project.first
|
88
|
+
project.meetings.each do |meeting|
|
89
|
+
puts meeting.title
|
90
|
+
end</code></pre>
|
91
|
+
|
92
|
+
You can also change the names of projects through these objects:
|
93
|
+
|
94
|
+
<pre><code>project.name = 'Sit downs'
|
95
|
+
project.save</code></pre>
|
96
|
+
|
97
|
+
h3. User Accounts
|
98
|
+
|
99
|
+
Your profile object allows you to change the email, name and timezone associated with that account:
|
100
|
+
|
101
|
+
<pre><code>profile.email = 'baz@foo.com'
|
102
|
+
profile.name = 'Bazza'
|
103
|
+
profile.timezone = 'Melbourne'
|
104
|
+
profile.save</code></pre>
|
105
|
+
|
106
|
+
You can also change the password, if you so desire:
|
107
|
+
|
108
|
+
<pre><code>profile.change_password '12345'</code></pre>
|
109
|
+
|
110
|
+
And there's also the ability to create completely new accounts:
|
111
|
+
|
112
|
+
<pre><code>Ketchup::Profile.create 'who@first.base.com', 'secret',
|
113
|
+
'name' => 'Who', 'timezone' => 'Dublin'</code></pre>
|
114
|
+
|
115
|
+
The name and timezone arguments are optional, though - and please note that you don't get a profile object back from that request, but will need to authenticate like normal to get access to that account's meetings.
|
116
|
+
|
117
|
+
h2. Contribution
|
118
|
+
|
119
|
+
Fork and patch as you see fit - and please send pull requests if you think it's useful for others. Don't forget to write specs and features first, and don't mess with the version numbers please (or at least: only do so in a different branch).
|
120
|
+
|
121
|
+
h2. Copyright
|
122
|
+
|
123
|
+
Copyright (c) 2010 "Pat Allan":http://freelancing-gods.com and "Paul Campbell":http://pabcas.com/, released under an open licence.
|
data/lib/ketchup.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Ketchup Ruby API
|
2
|
+
#
|
3
|
+
# @author Pat Allan
|
4
|
+
# @see http://useketchup.com
|
5
|
+
#
|
6
|
+
module Ketchup
|
7
|
+
# An exception thrown when invalid authentication details are provided.
|
8
|
+
#
|
9
|
+
class AccessDenied < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
# Creates a new profile authenticated against the Ketchup API. This is the
|
13
|
+
# recommended method to get access to an account's meetings, notes and items.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# profile = Ketchup.authenticate 'foo@bar.com', 'secret'
|
17
|
+
#
|
18
|
+
# @param [String] email The user's email address
|
19
|
+
# @param [String] password The user's passwords
|
20
|
+
# @return [Ketchup::Profile] A new profile instance
|
21
|
+
# @raise [Ketchup::AccessDenied] when the email or password is incorrect
|
22
|
+
#
|
23
|
+
def self.authenticate(email, password)
|
24
|
+
Ketchup::Profile.load(email, password)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'ketchup/api'
|
29
|
+
require 'ketchup/item'
|
30
|
+
require 'ketchup/item_array'
|
31
|
+
require 'ketchup/meeting'
|
32
|
+
require 'ketchup/meeting_array'
|
33
|
+
require 'ketchup/note'
|
34
|
+
require 'ketchup/note_array'
|
35
|
+
require 'ketchup/profile'
|
36
|
+
require 'ketchup/project'
|
data/lib/ketchup/api.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
# The direct interface with Ketchup's RESTful API. You should generally not have
|
4
|
+
# any need to use this class yourself, unless you're playing around with the
|
5
|
+
# internals. That said, it's a simple class - with get, post, put and delete
|
6
|
+
# instance methods for matching HTTP requests, that automatically include the
|
7
|
+
# access token.
|
8
|
+
#
|
9
|
+
# For pure access to the API, without any implicit authentication, use the class
|
10
|
+
# level methods, which are provided by the mixed-in HTTParty module.
|
11
|
+
#
|
12
|
+
# @see http://rdoc.info/projects/jnunemaker/httparty HTTParty
|
13
|
+
#
|
14
|
+
class Ketchup::API
|
15
|
+
include HTTParty
|
16
|
+
base_uri 'https://useketchup.com/api/v1'
|
17
|
+
|
18
|
+
attr_reader :access_token
|
19
|
+
|
20
|
+
# Creates a new API instance for the given profile, as determined by the email
|
21
|
+
# and password. This API object can then be used by all other objects to
|
22
|
+
# interact with the API without having to re-authenticate.
|
23
|
+
#
|
24
|
+
# @param [String] email The user's email address
|
25
|
+
# @param [String] password The user's password
|
26
|
+
# @raise [Ketchup::AccessDenied] if the email or password are incorrect
|
27
|
+
#
|
28
|
+
def initialize(email, password)
|
29
|
+
response = self.class.get '/profile.json', :basic_auth => {
|
30
|
+
:username => email,
|
31
|
+
:password => password
|
32
|
+
}
|
33
|
+
|
34
|
+
if response == 'Access Denied'
|
35
|
+
raise Ketchup::AccessDenied
|
36
|
+
else
|
37
|
+
@access_token = response['single_access_token']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Execute a GET request to the API server using the stored access token.
|
42
|
+
#
|
43
|
+
# @param [String] path The URL path
|
44
|
+
# @param [Hash] data Parameters for the request
|
45
|
+
# @return The web response
|
46
|
+
#
|
47
|
+
def get(path, data = {})
|
48
|
+
self.class.get path, :query => data.merge(:u => access_token)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Execute a POST request to the API server using the stored access token.
|
52
|
+
#
|
53
|
+
# @param [String] path The URL path
|
54
|
+
# @param [Hash] data Parameters for the request
|
55
|
+
# @return The web response
|
56
|
+
#
|
57
|
+
def post(path, data = {})
|
58
|
+
self.class.post path, :body => data.merge(:u => access_token)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Execute a PUT request to the API server using the stored access token.
|
62
|
+
#
|
63
|
+
# @param [String] path The URL path
|
64
|
+
# @param [Hash] data Parameters for the request
|
65
|
+
# @return The web response
|
66
|
+
#
|
67
|
+
def put(path, data = {})
|
68
|
+
self.class.put path, :body => data.merge(:u => access_token)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Execute a DELETE request to the API server using the stored access token.
|
72
|
+
#
|
73
|
+
# @param [String] path The URL path
|
74
|
+
# @param [Hash] data Parameters for the request
|
75
|
+
# @return The web response
|
76
|
+
#
|
77
|
+
def delete(path, data = {})
|
78
|
+
self.class.delete path, :body => data.merge(:u => access_token)
|
79
|
+
end
|
80
|
+
end
|
data/lib/ketchup/item.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Represents a list/agenda item in a meeting. Only the content is editable.
|
2
|
+
#
|
3
|
+
# If you want to change the order of items, you can do that using
|
4
|
+
# Ketchup::ItemArray (the meeting's item array).
|
5
|
+
#
|
6
|
+
class Ketchup::Item
|
7
|
+
attr_reader :shortcode_url, :updated_at, :created_at, :meeting_id, :notes,
|
8
|
+
:position, :meeting, :api
|
9
|
+
attr_accessor :content
|
10
|
+
|
11
|
+
# Create a new item for a given meeting, using an existing api connection. You
|
12
|
+
# generally won't want to call this yourself - the better interface to create
|
13
|
+
# new items is via a meeting's item array.
|
14
|
+
#
|
15
|
+
# However, if you are doing some internal hacking, it's worth noting that all
|
16
|
+
# keys for parameters in the hash should be strings, not symbols.
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# Ketchup::Item.new api, meeting, 'content' => "Treasurer's Report"
|
20
|
+
#
|
21
|
+
# @param [Ketchup::API] api The API connection
|
22
|
+
# @param [Ketchup::Meeting] meeting The meeting the item will belong to
|
23
|
+
# @param [Hash] params Any other details for the item.
|
24
|
+
# @see Ketchup::ItemArray#build
|
25
|
+
# @see Ketchup::ItemArray#create
|
26
|
+
#
|
27
|
+
def initialize(api, meeting, params = {})
|
28
|
+
@api = api
|
29
|
+
@meeting = meeting
|
30
|
+
|
31
|
+
overwrite params
|
32
|
+
|
33
|
+
@notes = Ketchup::NoteArray.new @api, self, (params['notes'] || [])
|
34
|
+
end
|
35
|
+
|
36
|
+
# Indicates whether the item exists on the server yet.
|
37
|
+
#
|
38
|
+
# @return [Boolean] True if the item does not exist on the server.
|
39
|
+
#
|
40
|
+
def new_record?
|
41
|
+
shortcode_url.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
# Saves the item to the server, whether it's a new item or an existing one.
|
45
|
+
# This does not save underlying notes.
|
46
|
+
#
|
47
|
+
def save
|
48
|
+
if new_record?
|
49
|
+
overwrite @api.post("/meetings/#{meeting.shortcode_url}/items.json",
|
50
|
+
'content' => content)
|
51
|
+
else
|
52
|
+
overwrite @api.put("/items/#{shortcode_url}.json", 'content' => content)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Deletes the item from the server. If the item has never been saved, this
|
57
|
+
# method will do nothing at all.
|
58
|
+
#
|
59
|
+
def destroy
|
60
|
+
return if new_record?
|
61
|
+
|
62
|
+
@api.delete "/items/#{shortcode_url}.json"
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def overwrite(attributes = {})
|
68
|
+
@shortcode_url = attributes['shortcode_url']
|
69
|
+
@created_at = attributes['created_at']
|
70
|
+
@updated_at = attributes['updated_at']
|
71
|
+
@meeting_id = attributes['meeting_id']
|
72
|
+
@position = attributes['position']
|
73
|
+
@content = attributes['content']
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# A collection of items for a specific meeting, and allows for the creation of
|
2
|
+
# new items, and re-ordering of the full set of items. It's really just a
|
3
|
+
# slightly special subclass of Array.
|
4
|
+
#
|
5
|
+
class Ketchup::ItemArray < Array
|
6
|
+
# Create a new ItemArray for a given api, meeting, and set of items. The set
|
7
|
+
# of items should be hashes taken from the API server, not actual item
|
8
|
+
# objects.
|
9
|
+
#
|
10
|
+
# Like many of the methods in this library, you really don't need to call this
|
11
|
+
# one yourself. A meeting object will create its own ItemArray without any
|
12
|
+
# help.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# Ketchup::ItemArray.new api, meeting, [{'content' => 'foo', #... }]
|
16
|
+
#
|
17
|
+
# @param [Ketchup::API] api A connected API instance
|
18
|
+
# @param [Ketchup::Meeting] meeting The meeting all items are attached to.
|
19
|
+
# @param [Array] items An array of hashes that map to attributes of items.
|
20
|
+
#
|
21
|
+
def initialize(api, meeting, items = [])
|
22
|
+
@api = api
|
23
|
+
@meeting = meeting
|
24
|
+
|
25
|
+
replace items.collect { |hash|
|
26
|
+
Ketchup::Item.new(@api, @meeting, hash)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Create a new unsaved item object. The only parameter you really need to
|
31
|
+
# worry about is the content - the rest is all internal values, managed by the
|
32
|
+
# API server.
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# meeting.items.build 'content' => 'Petty Cash'
|
36
|
+
#
|
37
|
+
# @param [Hash] params The item's details
|
38
|
+
# @return [Ketchup::Item] An unsaved item
|
39
|
+
#
|
40
|
+
def build(params = {})
|
41
|
+
item = Ketchup::Item.new @api, @meeting, params
|
42
|
+
push item
|
43
|
+
item
|
44
|
+
end
|
45
|
+
|
46
|
+
# Create a new (saved) item object. The only parameter you really need to
|
47
|
+
# worry about is the content - the rest is all internal values, managed by the
|
48
|
+
# API server.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# meeting.items.create 'content' => 'Petty Cash'
|
52
|
+
#
|
53
|
+
# @param [Hash] params The item's details
|
54
|
+
# @return [Ketchup::Item] An item, already saved to the server.
|
55
|
+
#
|
56
|
+
def create(params = {})
|
57
|
+
item = build(params)
|
58
|
+
item.save
|
59
|
+
item
|
60
|
+
end
|
61
|
+
|
62
|
+
# Re-order the items in this array, by passing them through in the order you
|
63
|
+
# would prefer. This makes the change directly to the API server, as well as
|
64
|
+
# within this array.
|
65
|
+
#
|
66
|
+
# Make sure you're passing in all the items that are in this array, and no
|
67
|
+
# others. This can't be used as a shortcut to add new items.
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# meeting.items.reorder second_item, fourth_item, first_item, third_item
|
71
|
+
#
|
72
|
+
# @param [Ketchup::Item] items The items of the array, in a new order.
|
73
|
+
# @raise ArgumentError if you don't provide the exact same set of items.
|
74
|
+
#
|
75
|
+
def reorder(*items)
|
76
|
+
if items.collect(&:shortcode_url).sort != collect(&:shortcode_url).sort
|
77
|
+
raise ArgumentError, 'cannot sort a different set of items'
|
78
|
+
end
|
79
|
+
|
80
|
+
@api.put "/meetings/#{@meeting.shortcode_url}/sort_items.json", {
|
81
|
+
'items' => items.collect(&:shortcode_url)
|
82
|
+
}
|
83
|
+
replace items
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# A Meeting - the cornerstone of Ketchup. This object tracks the meeting's
|
2
|
+
# key details: the title, whether it's public or not, the date, attendees, a
|
3
|
+
# description, location, project name, and the agenda items.
|
4
|
+
#
|
5
|
+
# While you won't want to create a new meeting from this class itself - it's far
|
6
|
+
# easier to do so using a profile's meetings array - this is a good reference
|
7
|
+
# point for changing and deleting meetings.
|
8
|
+
#
|
9
|
+
# @see Ketchup::MeetingArray#build
|
10
|
+
# @see Ketchup::MeetingArray#create
|
11
|
+
#
|
12
|
+
class Ketchup::Meeting
|
13
|
+
attr_reader :shortcode_url, :public_url, :user_id, :created_at, :updated_at,
|
14
|
+
:project_id, :items, :api
|
15
|
+
|
16
|
+
WriteableAttributes = [:title, :quick, :public, :date, :attendees,
|
17
|
+
:description, :project_name, :location]
|
18
|
+
attr_accessor *WriteableAttributes
|
19
|
+
|
20
|
+
# Create a new meeting, using an active API object. Keep in mind that all
|
21
|
+
# parameter keys must be provided as strings. The key attributes are the title
|
22
|
+
# and the date (the rest are optional).
|
23
|
+
#
|
24
|
+
# The date can be defined using natural language, and the server will figure
|
25
|
+
# out what you mean (just like when you create a meeting on the website).
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# Ketchup::Meeting.new api,
|
29
|
+
# 'title' => 'White Album Cover Brainstorming',
|
30
|
+
# 'date' => 'Tomorrow at 4pm',
|
31
|
+
# 'attendees' => 'John, Paul, George and Ringo',
|
32
|
+
# 'location' => 'Abbey Road',
|
33
|
+
# 'project_name' => 'New Releases'
|
34
|
+
#
|
35
|
+
# @param [Ketchup::API] api A connected API instance
|
36
|
+
# @param [Hash] params The attributes for the meeting.
|
37
|
+
#
|
38
|
+
def initialize(api, params = {})
|
39
|
+
@api = api
|
40
|
+
|
41
|
+
overwrite params
|
42
|
+
|
43
|
+
@items = Ketchup::ItemArray.new @api, self, (params['items'] || [])
|
44
|
+
end
|
45
|
+
|
46
|
+
# Saves the meeting to the server, whether it's a new meeting or an existing
|
47
|
+
# one. This does not save underlying items or notes.
|
48
|
+
#
|
49
|
+
def save
|
50
|
+
if new_record?
|
51
|
+
overwrite @api.post("/meetings.json", writeable_attributes)
|
52
|
+
else
|
53
|
+
overwrite @api.put("/meetings/#{shortcode_url}.json",
|
54
|
+
writeable_attributes)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Deletes the meeting from the server. If the meeting has never been saved,
|
59
|
+
# this method will do nothing at all.
|
60
|
+
#
|
61
|
+
def destroy
|
62
|
+
return if new_record?
|
63
|
+
|
64
|
+
@api.delete "/meetings/#{shortcode_url}.json"
|
65
|
+
end
|
66
|
+
|
67
|
+
# Indicates whether the meeting exists on the server yet.
|
68
|
+
#
|
69
|
+
# @return [Boolean] True if the meeting does not exist on the server.
|
70
|
+
#
|
71
|
+
def new_record?
|
72
|
+
shortcode_url.nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def overwrite(attributes)
|
78
|
+
@shortcode_url = attributes['shortcode_url']
|
79
|
+
@public_url = attributes['public_url']
|
80
|
+
@user_id = attributes['user_id']
|
81
|
+
@created_at = attributes['created_at']
|
82
|
+
@updated_at = attributes['updated_at']
|
83
|
+
@project_id = attributes['project_id']
|
84
|
+
|
85
|
+
WriteableAttributes.each do |attrib|
|
86
|
+
instance_variable_set "@#{attrib}".to_sym, attributes[attrib.to_s]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def writeable_attributes
|
91
|
+
WriteableAttributes.inject({}) do |hash, attrib|
|
92
|
+
hash[attrib.to_s] = instance_variable_get "@#{attrib}".to_sym
|
93
|
+
hash
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|