Issues (7)

lib/ringcentral-avatars/creator.rb (5 issues)

1
require 'avatarly'
2
require 'chunky_png'
3
require 'ruby_identicon'
4
5
require 'faraday'
6
require 'faraday_middleware-request-retry'
7
require 'logger'
8
require 'mime/types'
9
require 'ringcentral_sdk'
10
require 'tempfile'
11
12
module RingCentral
13
  module Avatars
14
    class Creator
0 ignored issues
show
This class should have a documentation comment as per coding style.
Loading history...
15
      DEFAULT_SIZE = 600
16
      DEFAULT_FORMAT = 'png'.freeze
17
      PNG_DEFAULT_METADATA = {
18
        'Description' => 'RingCentral Default Avatar'
19
      }.freeze
20
21
      attr_accessor :avatar_opts
22
      attr_accessor :avatars
23
      attr_accessor :client
24
      attr_accessor :extensions
25
      attr_accessor :png_metadata
26
      attr_accessor :retry
27
28
      ##
29
      # Requires RingCentralSdk instance
30
      # `:avatar_opts` is optional to pass-through options for Avatarly
31
      def initialize(client, opts = {})
32
        @client = client
33
        if !opts.key?(:initials_opts) && opts.key?(:avatar_opts)
34
          opts[:initials_opts] = opts[:avatar_opts]
35
        end
36
        if opts.key? :png_metadata
37
          opts[:png_metadata] = PNG_DEFAULT_METADATA.merge(opts[:png_metadata])
38
        else
39
          opts[:png_metadata] = PNG_DEFAULT_METADATA
40
        end
41
        opts[:logger] = @client.config.logger
42
        @retry = opts.key?(:retry) && opts[:retry] ? true : false
43
        opts[:retry] = @retry
44
        @avatars = RingCentral::Avatars::MultiAvatar.new opts
45
        @retry_util = FaradayMiddleware::Request::RetryUtil.new logger: client.config.logger
46
        load_extensions
47
      end
48
49
      ##
50
      # Convenience method for creating default avatars for all extensions
51
      # Defaults to not overwriting existing avatars
52
      def create_defaults(opts = {})
53
        opts[:overwrite] = false
54
        create_all opts
55
      end
56
57
      ##
58
      # Convenience method for creating avatars for all extensions
59
      # Defaults to overwriting existing avatar
60
      def create_all(opts = {})
61
        opts[:overwrite] = true unless opts.key?(:overwrite)
62
        @extensions.extensions_hash.each do |_ext_id, ext|
63
          create_avatar ext, opts
64
        end
65
        load_extensions
66
      end
67
68
      ##
69
      # Convenience method for creating avatar for authorized extension
70
      # Defaults to not overwriting existing avatar
71
      def create_mine(opts = {})
72
        try_req = true
73
        while try_req
74
          res_ext = @client.http.get 'account/~/extension/~'
75
          try_req = retry_status res_ext
76
        end
77
        res_avt = create_avatar res_ext.body, opts
78
        res_avt
79
      end
80
81
      ##
82
      # Create the avatar for the extension.
83
      # Defaults to not overwriting existing avatar
84
      def create_avatar(ext, opts = {})
85
        opts[:overwrite] = false unless opts.key?(:overwrite)
86
        if avatar?(ext) && !opts[:overwrite]
87
          return nil
88
        end
89
        url = "account/~/extension/#{ext['id']}/profile-image"
90
        res_avt = nil
91
        try_req = true
92
        while try_req
93
          image = @avatars.avatar_faraday_uploadio ext['name']
94
          res_avt = @client.http.put url, image: image
95
          try_req = retry_status res_avt
96
        end
97
        res_avt
98
      end
99
100
      def retry_status(res)
101
        return false unless @retry
102
        @retry_util.retry_status(res.status, res.headers['Retry-After'])
103
      end
104
105
      ##
106
      # Determines if extension has an existing avatar
107
      # Checks by looking for the presence of the `etag` property
108
      def avatar?(ext)
109
        ext['profileImage'].key?('etag') ? true : false
110
      end
111
112
      def load_extensions
113
        @extensions = RingCentralSdk::REST::Cache::Extensions.new client
114
        @extensions.retrieve_all
115
      end
116
117
      ##
118
      # Returns a list of avatar URLs which can be useful for testing purposes
119
      # Adding the current access token is optional
120
      def avatar_urls(opts = {})
121
        opts[:include_token] = false unless opts.key? :include_token
122
        urls = []
123
        @extensions.extensions_hash.keys.sort.each do |ext_id|
124
          ext = @extensions.extensions_hash[ext_id]
125
          urls.push avatar_url(ext, opts)
126
        end
127
        urls
128
      end
129
130
      def my_avatar_url(opts = {})
131
        opts[:include_token] = false unless opts.key? :include_token
132
        res = @client.http.get 'account/~/extension/~'
133
        avatar_url(res.body, opts)
134
      end
135
136
      def avatar_url(ext, opts = {})
137
        opts[:include_token] = false unless opts.key? :include_token
138
        token = @client.token.to_hash[:access_token]
139
        url = ext['profileImage']['uri']
140
        url += "?access_token=#{token}" if opts[:include_token]
141
        url
142
      end
143
    end
144
  end
145
end
146
147
module RingCentral
0 ignored issues
show
This class should have a documentation comment as per coding style.
Loading history...
148
  module Avatars
149
    class MultiAvatar
150
      DEFAULT_STYLE = 'initials'.freeze
151
      AVATARLY_DEFAULTS = {
152
        size: 600,
153
        format: 'png'
154
      }.freeze
155
      IDENTICON_DEFAULTS = {
156
        grid_size: 5,
157
        square_size: 70,
158
        background_color: 0xffffffff
159
      }.freeze
160
      IDENTICON_DEFAULT_FORMAT = 'png'.freeze
161
162
      def initialize(opts = {})
163
        @avatarly_opts =  inflate_avatarly_opts opts[:initials_opts]
164
        @identicon_opts = inflate_identicon_opts opts[:identicon_opts]
165
        @style = opts.key?(:style) ? opts[:style] : DEFAULT_STYLE
166
        @png_metadata = opts.key?(:png_metadata) ? opts[:png_metadata] : {}
167
        @logger = opts.key?(:logger) ? opts[:logger] : Logger.new(STDOUT)
168
      end
169
170 View Code Duplication
      def inflate_avatarly_opts(avatarly_opts = {})
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
171
        avatarly_opts = {} unless avatarly_opts.is_a? Hash
172
        AVATARLY_DEFAULTS.merge avatarly_opts
173
      end
174
175 View Code Duplication
      def inflate_identicon_opts(identicon_opts = {})
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
176
        identicon_opts = {} unless identicon_opts.is_a? Hash
177
        IDENTICON_DEFAULTS.merge identicon_opts
178
      end
179
180
      def avatar_blob(text, style = nil)
0 ignored issues
show
Your coding style requires you to prefer if/unless over the ternary operator if the expression spans multiple lines.
Loading history...
181
        style = @style if style.nil?
182
        blob = style == 'initials' \
183
          ? Avatarly.generate_avatar(text, @avatarly_opts) \
184
          : RubyIdenticon.create(text, @identicon_opts)
185
        inflate_avatar_blob_png blob
186
      end
187
188
      def inflate_avatar_blob_png(blob)
189
        return blob unless avatar_format == 'png' && @png_metadata
190
        img = ChunkyPNG::Image.from_blob blob
191
        img.metadata = @png_metadata
192
        img.to_blob
193
      end
194
195
      def avatar_temp_file(text, style = nil)
196
        blob = avatar_blob text, style
197
        file = Tempfile.new ['avatar', avatar_extension]
198
        file.binmode
199
        file.write blob
200
        file.flush
201
        file
202
      end
203
204
      def avatar_faraday_uploadio(text, style = nil)
205
        file = avatar_temp_file text, style
206
        @logger.debug "Building Avatar Temp File: #{file.path}"
207
        Faraday::UploadIO.new file.path, avatar_mime_type
208
      end
209
210
      def avatar_format
211
        @style == 'initials' ? @avatarly_opts[:format] : IDENTICON_DEFAULT_FORMAT
212
      end
213
214
      def avatar_mime_type
215
        types = MIME::Types.type_for avatar_format
216
        if types.empty?
217
          raise "Unknown avatar format: #{avatar_format}"
218
        end
219
        types[0].to_s
220
      end
221
222
      def avatar_extension
223
        ".#{avatar_format}"
224
      end
225
    end
226
  end
227
end
228