totter 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.travis.yml +4 -0
- data/Contributing.markdown +19 -0
- data/Gemfile +22 -0
- data/LICENSE +22 -0
- data/Rakefile +21 -0
- data/Readme.markdown +49 -0
- data/lib/totter.rb +26 -0
- data/lib/totter/client.rb +152 -0
- data/lib/totter/client/choices.rb +74 -0
- data/lib/totter/client/decisions.rb +91 -0
- data/lib/totter/client/slugs.rb +19 -0
- data/lib/totter/client/timelines.rb +16 -0
- data/lib/totter/client/users.rb +54 -0
- data/lib/totter/client/votes.rb +25 -0
- data/lib/totter/error.rb +51 -0
- data/lib/totter/version.rb +4 -0
- data/test/cassettes/choices/create_choice_upload.yml +85 -0
- data/test/cassettes/choices/create_for_image.yml +87 -0
- data/test/cassettes/choices/destroy.yml +122 -0
- data/test/cassettes/choices/show.yml +42 -0
- data/test/cassettes/decisions/analytics.yml +85 -0
- data/test/cassettes/decisions/create.yml +44 -0
- data/test/cassettes/decisions/destroy.yml +81 -0
- data/test/cassettes/decisions/flag.yml +81 -0
- data/test/cassettes/decisions/publish.yml +129 -0
- data/test/cassettes/decisions/show.yml +84 -0
- data/test/cassettes/decisions/unflag.yml +122 -0
- data/test/cassettes/slugs/show.yml +75 -0
- data/test/cassettes/timelines/global.yml +165 -0
- data/test/cassettes/users/following.yml +194 -0
- data/test/cassettes/users/me.yml +43 -0
- data/test/cassettes/users/user.yml +49 -0
- data/test/cassettes/votes/create.yml +96 -0
- data/test/support/client_macros.rb +5 -0
- data/test/test_helper.rb +24 -0
- data/test/totter/client/choices_test.rb +48 -0
- data/test/totter/client/decisions_test.rb +77 -0
- data/test/totter/client/slugs_test.rb +11 -0
- data/test/totter/client/timelines_test.rb +9 -0
- data/test/totter/client/users_test.rb +36 -0
- data/test/totter/client/votes_test.rb +15 -0
- data/test/totter/client_test.rb +31 -0
- data/test/totter_test.rb +17 -0
- data/totter.gemspec +24 -0
- metadata +155 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
## Submitting a Pull Request
|
2
|
+
|
3
|
+
1. [Fork the repository.][fork]
|
4
|
+
2. [Create a topic branch.][branch]
|
5
|
+
3. Add tests for your unimplemented feature or bug fix.
|
6
|
+
4. Run `bundle exec rake`. If your tests pass, return to step 3.
|
7
|
+
5. Implement your feature or bug fix.
|
8
|
+
6. Run `bundle exec rake`. If your tests fail, return to step 5.
|
9
|
+
7. Run `open coverage/index.html`. If your changes are not completely covered
|
10
|
+
by your tests, return to step 3.
|
11
|
+
8. Add documentation for your feature or bug fix.
|
12
|
+
9. Run `bundle exec rake doc`. If your changes are not 100% documented, go
|
13
|
+
back to step 8.
|
14
|
+
10. Add, commit, and push your changes.
|
15
|
+
11. [Submit a pull request.][pr]
|
16
|
+
|
17
|
+
[fork]: http://help.github.com/fork-a-repo/
|
18
|
+
[branch]: http://learn.github.com/p/branching.html
|
19
|
+
[pr]: http://help.github.com/send-pull-requests/
|
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Gem dependencies
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'rake', group: [:development, :test]
|
7
|
+
|
8
|
+
# Development dependencies
|
9
|
+
group :development do
|
10
|
+
gem 'yard'
|
11
|
+
gem 'redcarpet'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Testing dependencies
|
15
|
+
group :test do
|
16
|
+
gem 'minitest'
|
17
|
+
gem 'minitest-wscolor'
|
18
|
+
gem 'webmock', require: 'webmock/minitest'
|
19
|
+
gem 'vcr'
|
20
|
+
gem 'mocha', require: 'mocha/setup'
|
21
|
+
gem 'simplecov', require: false
|
22
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Seesaw Decisions Corporation
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
Rake::TestTask.new(:test) do |t|
|
6
|
+
t.libs << 'test'
|
7
|
+
t.pattern = 'test/**/*_test.rb'
|
8
|
+
end
|
9
|
+
task default: :test
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'yard'
|
13
|
+
YARD::Rake::YardocTask.new(:doc) do |task|
|
14
|
+
task.files = ['Readme.markdown', 'LICENSE', 'lib/**/*.rb']
|
15
|
+
task.options = [
|
16
|
+
'--output-dir', 'doc',
|
17
|
+
'--markup', 'markdown',
|
18
|
+
]
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
end
|
data/Readme.markdown
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Totter
|
2
|
+
|
3
|
+
Totter, as in teeter-totter, let's you work with the Seesaw API in Ruby.
|
4
|
+
|
5
|
+
All networking is done with Net::HTTP so you don't have to worry about version conflicts with whatever networking library you may be using.
|
6
|
+
|
7
|
+
Read the [documentation](http://rubydoc.info/github/seesawco/totter-rb/master/frames) online.
|
8
|
+
|
9
|
+
[![Build Status](https://travis-ci.org/seesawco/totter-rb.png?branch=master)](https://travis-ci.org/seesawco/totter-rb) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/seesawco/totter-rb)
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
``` ruby
|
16
|
+
gem 'totter'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
``` shell
|
22
|
+
$ bundle
|
23
|
+
```
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
``` shell
|
28
|
+
$ gem install totter
|
29
|
+
```
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
A client takes an optional access token when you initialize it. If you don't provide one, you can still use it to make unauthenticated requests. If you do provide one, it will set the authorization header for all requests.
|
34
|
+
|
35
|
+
``` ruby
|
36
|
+
> client = Totter::Client.new(access_token: 'your_access_token')
|
37
|
+
> current_user = client.me
|
38
|
+
> current_user.username
|
39
|
+
#=> "soffes"
|
40
|
+
> decision = client.decision(5, 3276)
|
41
|
+
#=> "Which lamp for the new apartment?"
|
42
|
+
> slug = client.slug('d/3I0n0g')
|
43
|
+
> slug.decision.user.username
|
44
|
+
#=> "soffes"
|
45
|
+
```
|
46
|
+
|
47
|
+
## Contributing
|
48
|
+
|
49
|
+
See the [contributing guide](Contributing.markdown).
|
data/lib/totter.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'totter/version'
|
2
|
+
require 'totter/client'
|
3
|
+
require 'totter/error'
|
4
|
+
|
5
|
+
# Totter, as in teeter-totter, let's you work with the Seesaw API in Ruby.
|
6
|
+
module Totter
|
7
|
+
class << self
|
8
|
+
# Alias for Totter::Client.new
|
9
|
+
#
|
10
|
+
# @return [Totter::Client]
|
11
|
+
def new(options = {})
|
12
|
+
Client.new(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Delegate to Totter::Client.new
|
16
|
+
def method_missing(method, *args, &block)
|
17
|
+
return super unless new.respond_to?(method)
|
18
|
+
new.send(method, *args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Forward respond_to? to Totter::Client.new
|
22
|
+
def respond_to?(method, include_private = false)
|
23
|
+
new.respond_to?(method, include_private) || super(method, include_private)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'uri'
|
4
|
+
require 'multi_json'
|
5
|
+
require 'hashie'
|
6
|
+
|
7
|
+
require 'totter/client/users'
|
8
|
+
require 'totter/client/decisions'
|
9
|
+
require 'totter/client/slugs'
|
10
|
+
require 'totter/client/timelines'
|
11
|
+
require 'totter/client/choices'
|
12
|
+
require 'totter/client/votes'
|
13
|
+
|
14
|
+
module Totter
|
15
|
+
# API client for interacting with the Seesaw API
|
16
|
+
class Client
|
17
|
+
include Totter::Client::Decisions
|
18
|
+
include Totter::Client::Users
|
19
|
+
include Totter::Client::Slugs
|
20
|
+
include Totter::Client::Timelines
|
21
|
+
include Totter::Client::Choices
|
22
|
+
include Totter::Client::Votes
|
23
|
+
|
24
|
+
attr_reader :access_token
|
25
|
+
attr_reader :api_scheme
|
26
|
+
attr_reader :api_host
|
27
|
+
attr_reader :api_version
|
28
|
+
|
29
|
+
# Initialize a new client.
|
30
|
+
#
|
31
|
+
# @param options [Hash] optionally specify `:access_token`, `:api_scheme`, `:api_host`, `:api_version`, or `:client_token`
|
32
|
+
def initialize(options = {})
|
33
|
+
options = { access_token: options } if options.is_a? String
|
34
|
+
|
35
|
+
@access_token = options[:access_token] if options[:access_token]
|
36
|
+
@api_scheme = (options[:api_scheme] or 'https')
|
37
|
+
@api_host = (options[:api_host] or 'api.seesaw.co')
|
38
|
+
@api_version = (options[:api_version] or 1)
|
39
|
+
@client_token = options[:client_token] if options[:client_token]
|
40
|
+
end
|
41
|
+
|
42
|
+
# API base URL.
|
43
|
+
#
|
44
|
+
# @return [String] API base URL
|
45
|
+
def base_url
|
46
|
+
"#{@api_scheme}://#{@api_host}/v#{@api_version}/"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Is the client has an access token.
|
50
|
+
#
|
51
|
+
# @return [Boolean] true if it is using one and false if it is not
|
52
|
+
def authenticated?
|
53
|
+
@access_token != nil and @access_token.length > 0
|
54
|
+
end
|
55
|
+
|
56
|
+
# Is the client using SSL.
|
57
|
+
#
|
58
|
+
# @return [Boolean] true if it is using SSL and false if it is not
|
59
|
+
def ssl?
|
60
|
+
@api_scheme == 'https'
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def http
|
66
|
+
return @http if @http
|
67
|
+
|
68
|
+
uri = URI.parse(self.base_url)
|
69
|
+
@http = Net::HTTP.new(uri.host, uri.port)
|
70
|
+
@http.use_ssl = self.ssl?
|
71
|
+
@http
|
72
|
+
end
|
73
|
+
|
74
|
+
def request(method, path, params = nil)
|
75
|
+
# Build request
|
76
|
+
request = build_request(method, URI.parse("#{self.base_url}#{path}"))
|
77
|
+
|
78
|
+
# Add headers
|
79
|
+
request['Authorization'] = "Bearer #{self.access_token}" if authenticated?
|
80
|
+
request['X-Seesaw-Client-Token'] = @client_token if @client_token
|
81
|
+
request['Content-Type'] = 'application/json'
|
82
|
+
|
83
|
+
# Add params as JSON if they exist
|
84
|
+
request.body = MultiJson.dump(params) if method == :post and params
|
85
|
+
|
86
|
+
# Request
|
87
|
+
response = http.request(request)
|
88
|
+
|
89
|
+
# Check for errors
|
90
|
+
handle_error(response)
|
91
|
+
|
92
|
+
# Return the raw response object
|
93
|
+
response
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_request(method, uri)
|
97
|
+
case method
|
98
|
+
when :get
|
99
|
+
Net::HTTP::Get.new(uri.request_uri)
|
100
|
+
when :post
|
101
|
+
Net::HTTP::Post.new(uri.request_uri)
|
102
|
+
when :put
|
103
|
+
Net::HTTP::Put.new(uri.request_uri)
|
104
|
+
when :delete
|
105
|
+
Net::HTTP::Delete.new(uri.request_uri)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def handle_error(response)
|
110
|
+
# Find error or return
|
111
|
+
return unless error = Totter::ERROR_MAP[response.code.to_i]
|
112
|
+
|
113
|
+
# Try to add a useful message
|
114
|
+
message = nil
|
115
|
+
begin
|
116
|
+
message = MultiJson.load(response.body)['error_description']
|
117
|
+
rescue MultiJson::DecodeError => e
|
118
|
+
end
|
119
|
+
|
120
|
+
# Raise error
|
121
|
+
raise error.new(message)
|
122
|
+
end
|
123
|
+
|
124
|
+
def json_request(*args)
|
125
|
+
# Preform request
|
126
|
+
response = request(*args)
|
127
|
+
|
128
|
+
# Parse JSON
|
129
|
+
object = MultiJson.load(response.body)
|
130
|
+
|
131
|
+
# Hash
|
132
|
+
return Hashie::Mash.new(object) if object.is_a? Hash
|
133
|
+
|
134
|
+
# Array
|
135
|
+
return object.map { |h| Hashie::Mash.new(h) } if object.is_a? Array
|
136
|
+
|
137
|
+
# Fallback incase it's not a hash or array
|
138
|
+
object
|
139
|
+
end
|
140
|
+
|
141
|
+
def boolean_from_response(*args)
|
142
|
+
response = request(*args)
|
143
|
+
(200..299).include? response.code.to_i
|
144
|
+
end
|
145
|
+
|
146
|
+
[:get, :post, :put, :delete].each do |method|
|
147
|
+
define_method method do |*args|
|
148
|
+
json_request(method, *args)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Totter
|
2
|
+
class Client
|
3
|
+
# Client methods for working with choices
|
4
|
+
module Choices
|
5
|
+
# Get a single choice
|
6
|
+
#
|
7
|
+
# @param user_id [Numeric] The choice's decision's user id
|
8
|
+
# @param decision_id [Numeric] The choice's decision's id
|
9
|
+
# @param choice_id [Numeric] The choice's id
|
10
|
+
# @return [Hashie::Mash]
|
11
|
+
# @example
|
12
|
+
# Seesaw.choice(1, 1, 1)
|
13
|
+
def choice(user_id, decision_id, choice_id)
|
14
|
+
get "users/#{user_id}/decisions/#{decision_id}/choices/#{choice_id}"
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# Create a new choice using a supplied image url
|
19
|
+
#
|
20
|
+
# @param user_id [Numeric] The choice's decision's user id
|
21
|
+
# @param decision_id [Numeric] The choice's decision's id
|
22
|
+
# @param options [Hash]
|
23
|
+
# @option options [String] :image_url The image url (required)
|
24
|
+
# @option options [String] :subject The image label
|
25
|
+
# @option options [String] :link_url A link to this image's page
|
26
|
+
# @option options [String] :link_title The title of a link to this image's page
|
27
|
+
# @return [Hashie::Mash]
|
28
|
+
# @example
|
29
|
+
# Seesaw.create_choice_for_image(1, 1, image_url: 'http://recess.s3.amazonaws.com/default_avatars/v1/photo_1.png', \
|
30
|
+
# subject: 'Sample Avatar', link_url: 'https://seesaw.co', link_title: 'Seesaw')
|
31
|
+
def create_choice_for_image(user_id, decision_id, options = {})
|
32
|
+
raise ArgumentError.new('image_url option is required') unless options[:image_url]
|
33
|
+
|
34
|
+
data = {
|
35
|
+
choice: {
|
36
|
+
type: 'image',
|
37
|
+
image_url: options[:image_url],
|
38
|
+
subject: options[:subject],
|
39
|
+
meta: {
|
40
|
+
link_url: options[:link_url],
|
41
|
+
link_title: options[:link_title]
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
post "users/#{user_id}/decisions/#{decision_id}/choices", data
|
47
|
+
end
|
48
|
+
|
49
|
+
# Create a new choice upload. Resulting hash contains an #upload parameter
|
50
|
+
# providing keys necessary to perform a signed S3 upload.
|
51
|
+
#
|
52
|
+
# @param user_id [Numeric] The choice's decision's user id
|
53
|
+
# @param decision_id [Numeric] The choice's decision's id
|
54
|
+
# @return [Hashie::Mash]
|
55
|
+
# @example
|
56
|
+
# Seesaw.create_choice_upload(1, 1)
|
57
|
+
def create_choice_upload(user_id, decision_id)
|
58
|
+
post "users/#{user_id}/decisions/#{decision_id}/choices"
|
59
|
+
end
|
60
|
+
|
61
|
+
# Destroy a choice
|
62
|
+
#
|
63
|
+
# @param user_id [Numeric] The choice's decision's user id
|
64
|
+
# @param decision_id [Numeric] The choice's decision's id
|
65
|
+
# @param choice_id [Numeric] The choice's id
|
66
|
+
# @return [Boolean] True if follow was successful, false otherwise.
|
67
|
+
# @example
|
68
|
+
# Seesaw.destroy_choice(1, 1)
|
69
|
+
def destroy_choice(user_id, decision_id, choice_id)
|
70
|
+
boolean_from_response :delete, "users/#{user_id}/decisions/#{decision_id}/choices/#{choice_id}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Totter
|
2
|
+
class Client
|
3
|
+
# Client methods for working with decisions
|
4
|
+
module Decisions
|
5
|
+
# Get a single decision
|
6
|
+
#
|
7
|
+
# @param user_id [Numeric] The decision's user id
|
8
|
+
# @param decision_id [Numeric] The decision's id
|
9
|
+
# @return [Hashie::Mash]
|
10
|
+
# @example
|
11
|
+
# Seesaw.decision(1, 1)
|
12
|
+
def decision(user_id, decision_id)
|
13
|
+
get "users/#{user_id}/decisions/#{decision_id}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Create a decision
|
17
|
+
#
|
18
|
+
# @param user_id [Numeric] A Seesaw user id
|
19
|
+
# @return [Hashie::Mash]
|
20
|
+
# @example
|
21
|
+
# Seesaw.create_decision(1)
|
22
|
+
def create_decision(user_id)
|
23
|
+
post "users/#{user_id}/decisions"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Publish a decision
|
27
|
+
#
|
28
|
+
# @param user_id [Numeric] The decision's user id
|
29
|
+
# @param decision_id [Numeric] The decision's id
|
30
|
+
# @param options [Hash] Decision options
|
31
|
+
# @option options [String] :question The question for the decision
|
32
|
+
# @option options [Numeric] :latitude Latitude
|
33
|
+
# @option options [Numeric] :longitude Longitude
|
34
|
+
# @option options [Hash] :choice_attributes Additional attributes for decision choices
|
35
|
+
# @return [Hashie::Mash]
|
36
|
+
# @example
|
37
|
+
# Seesaw.publish_decision(1, 1, question: 'Why is the sky blue?')
|
38
|
+
def publish_decision(user_id, decision_id, options = {})
|
39
|
+
decision_options = {
|
40
|
+
decision: options
|
41
|
+
}
|
42
|
+
|
43
|
+
post "users/#{user_id}/decisions/#{decision_id}/publish", decision_options
|
44
|
+
end
|
45
|
+
|
46
|
+
# Destroy a decision
|
47
|
+
#
|
48
|
+
# @param user_id [Numeric] The decision's user id
|
49
|
+
# @param decision_id [Numeric] The decision's id
|
50
|
+
# @return [Boolean] True if follow was successful, false otherwise.
|
51
|
+
# @example
|
52
|
+
# Seesaw.destroy_decision(1, 1)
|
53
|
+
def destroy_decision(user_id, decision_id)
|
54
|
+
boolean_from_response :delete, "users/#{user_id}/decisions/#{decision_id}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get decision analytics
|
58
|
+
#
|
59
|
+
# @param user_id [Numeric] The decision's user id
|
60
|
+
# @param decision_id [Numeric] The decision's id
|
61
|
+
# @return [Hashie::Mash]
|
62
|
+
# @example
|
63
|
+
# Seesaw.decision_analytics(1, 1)
|
64
|
+
def decision_analytics(user_id, decision_id)
|
65
|
+
get "users/#{user_id}/decisions/#{decision_id}/analytics"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Flag a decision for content review
|
69
|
+
#
|
70
|
+
# @param user_id [Numeric] The decision's user id
|
71
|
+
# @param decision_id [Numeric] The decision's id
|
72
|
+
# @return [Boolean] True if follow was successful, false otherwise.
|
73
|
+
# @example
|
74
|
+
# Seesaw.flag_decision(1, 1)
|
75
|
+
def flag_decision(user_id, decision_id)
|
76
|
+
boolean_from_response :post, "users/#{user_id}/decisions/#{decision_id}/flag"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Unflag a decision for content review
|
80
|
+
#
|
81
|
+
# @param user_id [Numeric] The decision's user id
|
82
|
+
# @param decision_id [Numeric] The decision's id
|
83
|
+
# @return [Boolean] True if follow was successful, false otherwise.
|
84
|
+
# @example
|
85
|
+
# Seesaw.unflag_decision(1, 1)
|
86
|
+
def unflag_decision(user_id, decision_id)
|
87
|
+
boolean_from_response :post, "users/#{user_id}/decisions/#{decision_id}/unflag"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|