fastlane-plugin-devresponse 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3004f000da9c80de39739afdd6e05113c18c013f
4
+ data.tar.gz: 48cb8b1f835ec924f873044173f6bfd520460b0c
5
+ SHA512:
6
+ metadata.gz: a8a15c3ac56b09e8c86fd12ad649b8b6e6ecb604005bb4d249a82f8bc9270e59dc81cc429e95404b71ac0310b76234321b85cb06c50f5b056a9dab410b5161db
7
+ data.tar.gz: 485d55b5b2da4e76a795e22a5ac59e8ddab53bdd5f2dbcac1047fa35e0435ad1c9a45d790811aa01cfaf50ed8165e60d22fb0768cd3b3825fe3a8336d7f7a037
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ # DON'T BE A DICK PUBLIC LICENSE
2
+
3
+ > Version 1.1, December 2016
4
+
5
+ > Copyright (C) 2017 Helmut Januschka
6
+
7
+ Everyone is permitted to copy and distribute verbatim or modified
8
+ copies of this license document.
9
+
10
+ > DON'T BE A DICK PUBLIC LICENSE
11
+ > TERMS AND CONDITIONS FOR COPYING, DICCCCCSTRIBUTION AND MODIFICATION
12
+
13
+ 1. Do whatever you like with the original Cwork, just don't be a dick.
14
+
15
+ Being a dick includes - but is not limited to - the following instances:
16
+ C
17
+ 1a. Outright copyright infringement - Don't just copy this and change the name.
18
+ 1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick.
19
+ 1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick.
20
+
21
+ 2. If you become rich through modifications, related works/services, or supporting the original work,
22
+ share the love. Only a dick would make loads off this work and not buy the original work's
23
+ creator(s) a pint.
24
+
25
+ 3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes
26
+ you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back.
@@ -0,0 +1,40 @@
1
+ # devresponse plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-devresponse)
4
+
5
+ Enables you to retreive app-reviews and also answer them
6
+
7
+ # Sample
8
+
9
+ ```ruby
10
+ lane :reply_all_unanswered do
11
+ Spaceship::Tunes.login("helmut@januschka.com")
12
+ app = Spaceship::Application.find("krone.at-fivexfive")
13
+
14
+
15
+ # get all reviews from AT
16
+ reviews = app.ratings.reviews("AT")
17
+
18
+ # iterate over each review - thx the 4+ and apologize all below
19
+ reviews.each do | review |
20
+ if review.rating >= 4
21
+ response_message = "Many Thx for your kind feedback and the awesome rating 🎉"
22
+ else
23
+ response_message = "We are really sorry 💔 that you have troubles with the app - feel free to contact us directly at app@domain.com - to get technical assistance!"
24
+ end
25
+ # which not yet have gotten a dev response
26
+ unless review.responded?
27
+ # respond to this user
28
+ review.developer_response.create!(response_message)
29
+ end
30
+ end
31
+
32
+ # here is a sample of editing a existing developer response
33
+ if reviews.first.responded?
34
+ reviews.first.developer_response.update!("First you where awesome 👏 but now you are 🚀")
35
+ end
36
+ end
37
+
38
+ ```
39
+
40
+ run with `fastlane reply_all_unanswered`
@@ -0,0 +1,19 @@
1
+ require 'fastlane/plugin/devresponse/version'
2
+
3
+ module Fastlane
4
+ module Devresponse
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default we want to import all available actions and helpers
13
+ # A plugin can contain any number of actions and plugins
14
+ Fastlane::Devresponse.all_classes.each do |current|
15
+ require current
16
+ end
17
+
18
+ require "fastlane/plugin/devresponse/patches/spaceship/tunes/app_ratings"
19
+ require "fastlane/plugin/devresponse/patches/spaceship/tunes/tunes_client"
@@ -0,0 +1,25 @@
1
+ module Fastlane
2
+ module Actions
3
+ class DevresponseAction < Action
4
+ def self.run(params)
5
+ end
6
+
7
+ def self.description
8
+ "Devresponse patcher"
9
+ end
10
+
11
+ def self.available_options
12
+ [
13
+ ]
14
+ end
15
+
16
+ def self.authors
17
+ ["hjanuschka"]
18
+ end
19
+
20
+ def self.is_supported?(platform)
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,89 @@
1
+ module Spaceship
2
+ module Tunes
3
+ class AppRatings < TunesBase
4
+ # @return (Array) of Review Objects
5
+ def reviews(store_front, versionId = '')
6
+ raw_reviews = client.get_reviews(application.apple_id, application.platform, store_front, versionId)
7
+ raw_reviews.map do |review|
8
+ review["value"]["application"] = self.application
9
+ AppReview.factory(review["value"])
10
+ end
11
+ end
12
+ end
13
+ class DeveloperResponse < TunesBase
14
+ attr_reader :id
15
+ attr_reader :response
16
+ attr_reader :last_modified
17
+ attr_reader :hidden
18
+ attr_reader :state
19
+ attr_accessor :application
20
+ attr_accessor :review_id
21
+
22
+ attr_mapping({
23
+ 'responseId' => :id,
24
+ 'response' => :response,
25
+ 'lastModified' => :last_modified,
26
+ 'isHidden' => :hidden,
27
+ 'pendingState' => :state
28
+ })
29
+
30
+ def create!(text)
31
+ client.create_developer_response!(app_id: application.apple_id, platform: application.platform, review_id: review_id, response: text)
32
+ end
33
+
34
+ def update!(text)
35
+ client.update_developer_response!(app_id: application.apple_id, platform: application.platform, review_id: review_id, response_id: id, response: text)
36
+ end
37
+ end
38
+
39
+ class AppReview < TunesBase
40
+ attr_accessor :application
41
+ attr_reader :rating
42
+ attr_reader :id
43
+ attr_reader :title
44
+ attr_reader :review
45
+ attr_reader :nickname
46
+ attr_reader :store_front
47
+ attr_reader :app_version
48
+ attr_reader :last_modified
49
+ attr_reader :helpful_views
50
+ attr_reader :total_views
51
+ attr_reader :edited
52
+ attr_reader :raw_developer_response
53
+ attr_accessor :developer_response
54
+
55
+ attr_mapping({
56
+ 'id' => :id,
57
+ 'rating' => :rating,
58
+ 'title' => :title,
59
+ 'review' => :review,
60
+ 'nickname' => :nickname,
61
+ 'storeFront' => :store_front,
62
+ 'appVersionString' => :app_version,
63
+ 'lastModified' => :last_modified,
64
+ 'helpfulViews' => :helpful_views,
65
+ 'totalViews' => :total_views,
66
+ 'developerResponse' => :raw_developer_response,
67
+ 'edited' => :edited
68
+ })
69
+ class << self
70
+ # Create a new object based on a hash.
71
+ # This is used to create a new object based on the server response.
72
+ def factory(attrs)
73
+ obj = self.new(attrs)
74
+ response_attrs = {}
75
+ response_attrs = obj.raw_developer_response if obj.raw_developer_response
76
+ response_attrs[:application] = obj.application
77
+ response_attrs[:review_id] = obj.id
78
+ obj.developer_response = DeveloperResponse.factory(response_attrs)
79
+ return obj
80
+ end
81
+ end
82
+
83
+ def responded?
84
+ return true if raw_developer_response
85
+ false
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,51 @@
1
+ module Spaceship
2
+ class TunesClient
3
+ def create_developer_response!(app_id: nil, platform: "ios", review_id: nil, response: nil)
4
+ raise "app_id is required" unless app_id
5
+ raise "review_id is required" unless review_id
6
+ raise "response is required" unless response
7
+
8
+ data = {
9
+ responseText: response,
10
+ reviewId: review_id
11
+ }
12
+ request(:post) do |req|
13
+ req.url "ra/apps/#{app_id}/platforms/#{platform}/reviews/#{review_id}/responses"
14
+ req.body = data.to_json
15
+ req.headers['Content-Type'] = 'application/json'
16
+ end
17
+ end
18
+
19
+ def update_developer_response!(app_id: nil, platform: "ios", review_id: nil, response_id: nil, response: nil)
20
+ raise "app_id is required" unless app_id
21
+ raise "review_id is required" unless review_id
22
+ raise "response_id is required" unless response_id
23
+ raise "response is required" unless response
24
+
25
+ data = {
26
+ responseText: response
27
+ }
28
+ request(:put) do |req|
29
+ req.url "ra/apps/#{app_id}/platforms/#{platform}/reviews/#{review_id}/responses/#{response_id}"
30
+ req.body = data.to_json
31
+ req.headers['Content-Type'] = 'application/json'
32
+ end
33
+ end
34
+
35
+ def get_reviews(app_id, platform, storefront, versionId = '')
36
+ index = 0
37
+ per_page = 100 # apple default
38
+ all_reviews = []
39
+ loop do
40
+ r = request(:get, "ra/apps/#{app_id}/platforms/#{platform}/reviews?storefront=#{storefront}&versionId=#{versionId}&index=#{index}")
41
+ all_reviews.concat(parse_response(r, 'data')['reviews'])
42
+ if all_reviews.count < parse_response(r, 'data')['reviewCount']
43
+ index += per_page
44
+ else
45
+ break
46
+ end
47
+ end
48
+ all_reviews
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,19 @@
1
+ require 'fastlane/plugin/devresponse/version'
2
+
3
+ module Fastlane
4
+ module Devresponse
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default we want to import all available actions and helpers
13
+ # A plugin can contain any number of actions and plugins
14
+ Fastlane::Devresponse.all_classes.each do |current|
15
+ require current
16
+ end
17
+
18
+ require File.expand_path("**/patches/spaceship/tunes/app_ratings")
19
+ require File.expand_path("**/patches/spaceship/tunes/tunes_client")
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module Devresponse
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-devresponse
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Helmut Januschka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fastlane
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 2.10.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 2.10.0
97
+ description:
98
+ email: helmut@januschka.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - LICENSE
104
+ - README.md
105
+ - lib/fastlane/plugin/devresponse.rb
106
+ - lib/fastlane/plugin/devresponse/actions/devresponse.rb
107
+ - lib/fastlane/plugin/devresponse/patches/spaceship/tunes/app_ratings.rb
108
+ - lib/fastlane/plugin/devresponse/patches/spaceship/tunes/tunes_client.rb
109
+ - lib/fastlane/plugin/devresponse/patches/tunes_client.rb
110
+ - lib/fastlane/plugin/devresponse/version.rb
111
+ homepage:
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.6.11
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Enables Spaceship to deal with developer response
135
+ test_files: []