file-convert 0.0.1

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: 4ab5545b631ce1b728c55f51238e30c3f55e3459
4
+ data.tar.gz: 6c0170fd117a7030326857e34124102dbe57fe37
5
+ SHA512:
6
+ metadata.gz: 94c4e4c7dfec2285946452d565195756dfd761e9ffd3d448d5bf098ac30c667e0bcf17dddf059620f7865687d9a10aa4f44cdc996b508105d7740023feeb20e9
7
+ data.tar.gz: 33172e266792bd45830551e68d0a6641a350363189b91697d298d9acb48ea37b928beaace5c37a98e33602cb39bfff7e9c00b25e5f920c9fb43b45e8a9270014
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Roman Ernst and tolingo GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,79 @@
1
+ # file-convert [![Build Status](https://travis-ci.org/tolingo/file-convert.svg?branch=feature%2Ffix-specs-and-refactor)](https://travis-ci.org/tolingo/file-convert) [![Test Coverage](https://codeclimate.com/repos/53f4984b6956807963019c1a/badges/7aef33ebfd86eb320a98/coverage.svg)](https://codeclimate.com/repos/53f4984b6956807963019c1a/feed) [![Code Climate](https://codeclimate.com/repos/53f4984b6956807963019c1a/badges/7aef33ebfd86eb320a98/gpa.svg)](https://codeclimate.com/repos/53f4984b6956807963019c1a/feed) [![Dependency Status](https://gemnasium.com/tolingo/file-convert.svg)](https://gemnasium.com/tolingo/file-convert)
2
+
3
+ > Use google-api-ruby-client and Google Drive to convert files from one mime-type to another.
4
+ For available formats see [Google Drive API Export Formats](https://developers.google.com/drive/web/integrate-open#open_and_convert_google_docs_in_your_app).
5
+
6
+ ## Installation
7
+
8
+ Simply add it to your Gemfile:
9
+
10
+ ```ruby
11
+ gem 'file-convert'
12
+ ```
13
+
14
+ ## Config
15
+
16
+ ### Via initializer
17
+
18
+ `FileConvert` exposes `.configure` which accepts a block and passes the config hash.
19
+ *Example*:
20
+
21
+ ```ruby
22
+ FileConvert.configure do |config|
23
+ config['google_service_account'] = {
24
+ 'email' => '<strange-hash>@developer.gserviceaccount.com',
25
+ 'pkcs12_file_path' => 'config/file_convert_key.p12'
26
+ }
27
+ end
28
+ ```
29
+
30
+ ### Via YAML
31
+
32
+ You need to add a YAML configuration file to `/config/file_convert.yml` that looks like `config/file_convert.sample.yml`.
33
+
34
+ In order to communicate with the Google API, `file_convert` requires a google developer email Address (`email`) and `pkcs12_file_path`.
35
+
36
+ Visit [Google Developers Console](console.developers.google.com) and check **Credentials**.
37
+ Here you can add a *new Client ID*. Select **Service Account** as application type.
38
+
39
+ You should now be able to download your *P12 key* and see your *developer email address*.
40
+ Place the *P12 key* somewhere accessible for your app and provide the location to the config. The sample config assumes your *P12 key* is located in `/config/file_convert_key.p12`.
41
+
42
+ Sample config as in `file_convert.samle.yml`:
43
+ ```yaml
44
+ file_convert:
45
+ google_service_account:
46
+ email: '<strange-hash>@developer.gserviceaccount.com'
47
+ pkcs12_file_path: 'config/file_convert_key.p12'
48
+ ```
49
+
50
+ ## Examples
51
+
52
+ ```ruby
53
+ # converts `path_to_some_file` from <txt> to <pdf>
54
+ conversion = FileConvert.convert('path_to_some_file.txt', 'text/plain', 'application/pdf')
55
+ # converted body is accessible via `#body`
56
+ conversion.body
57
+ # .. or define a path to save the converted document to
58
+ conversion.save('path_to_new_file.pdf')
59
+ ```
60
+
61
+ ## Specs
62
+
63
+ * `$ bundle exec rake` for `rspec` and `rubocop`.
64
+ * `$ bundle exec rake build` to also run the `integration` tests located at `spec/integration/**/*_integration.rb`.
65
+ Note that you need to have a valid `config/file_convert.yml` present for these tests to work,
66
+ since we want to actually test the integration with the Google API here. (Do not worry, TravisCI will run these test as well.)
67
+
68
+ ## Contributing
69
+
70
+ In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using the ways described [above](#specs).
71
+
72
+ ## Next Steps
73
+
74
+ * Enable OCR if necessary when uploading files
75
+ * Add CLI
76
+ * Add different adapter than Google?
77
+
78
+ ## License
79
+ file-convert is Copyright © 2014 [Roman Ernst](http://farbenmeer.net) and [tolingo GmbH](http://tolingo.com) and may be redistributed under the terms specified in the [LICENSE](https://github.com/tolingo/file-convert/blob/master/LICENSE) file.
@@ -0,0 +1,34 @@
1
+ module FileConvert
2
+ require 'file_convert/version'
3
+ require 'file_convert/exception'
4
+ require 'file_convert/configure'
5
+ require 'file_convert/client'
6
+ require 'file_convert/file'
7
+ require 'file_convert/upload'
8
+ require 'file_convert/conversion'
9
+
10
+ extend FileConvert::Configure
11
+
12
+ FileConvert::Configure.init_config!
13
+
14
+ ###
15
+ # @param [String] file_path
16
+ # Source file for conversions
17
+ # @param [String]
18
+ # Source file mime-type
19
+ # @param [String]
20
+ # Target file mime-type (converion target)
21
+ #
22
+ # @return [FileConvert::Conversion]
23
+ def self.convert(file_path, source_mime_type, target_mime_type)
24
+ upload = FileConvert::Upload.new(client, file_path, source_mime_type)
25
+ FileConvert::Conversion.new(client, upload.file, target_mime_type)
26
+ end
27
+
28
+ ###
29
+ # Initialize a new FileConvert::Client
30
+ def self.client
31
+ fail Exception::MissingConfig unless config_present?
32
+ @client ||= FileConvert::Client.new
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ module FileConvert
2
+ require 'google/api_client'
3
+
4
+ class Client < Google::APIClient
5
+ APP_OPTIONS = {
6
+ application_name: 'file-convert',
7
+ application_version: FileConvert::Version::STRING
8
+ }
9
+
10
+ attr_reader :drive
11
+
12
+ ###
13
+ # Inherits from Google::APIClient
14
+ # Basically wraps authentiation for simple configuration
15
+ #
16
+ # @return [FileConvert::Client] (inherits from Google::APIClient)
17
+ def initialize
18
+ gaccount = FileConvert.config['google_service_account']
19
+ gaccount['auth_url'] ||= 'https://www.googleapis.com/auth/drive'
20
+
21
+ key = load_key gaccount['pkcs12_file_path'], 'notasecret'
22
+ asserter = get_asserter gaccount['email'], gaccount['auth_url'], key
23
+
24
+ super(APP_OPTIONS).tap do |client|
25
+ client.authorization = asserter.authorize
26
+ @drive = client.discovered_api('drive', 'v2')
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def load_key(path, secret)
33
+ Google::APIClient::PKCS12.load_key(path, secret)
34
+ end
35
+
36
+ def get_asserter(email, auth_url, key)
37
+ Google::APIClient::JWTAsserter.new email, auth_url, key
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ module FileConvert
2
+ module Configure
3
+ require 'yaml'
4
+
5
+ DEFAULT_CONFIG_PATH = 'config/file_convert.yml'
6
+
7
+ def self.config_yaml_present?
8
+ ::File.exist?(DEFAULT_CONFIG_PATH)
9
+ end
10
+
11
+ def self.config_from_yaml
12
+ ::File.open(DEFAULT_CONFIG_PATH) do |file|
13
+ YAML.load(file)['file_convert']
14
+ end
15
+ end
16
+
17
+ def self.config
18
+ @@config
19
+ end
20
+
21
+ ###
22
+ # Loads config/file_convert.yml['file_convert'] into Config
23
+ # Or defaults to empty Hash if config file is not present
24
+ def self.init_config!
25
+ @@config = config_yaml_present? ? config_from_yaml : {}
26
+ end
27
+
28
+ def configure
29
+ yield config
30
+ end
31
+
32
+ def config
33
+ Configure.config
34
+ end
35
+
36
+ def config_present?
37
+ provider = 'google_service_account'
38
+ config.is_a?(Hash) && config.key?(provider)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,70 @@
1
+ module FileConvert
2
+ class Conversion
3
+ attr_reader :file
4
+ attr_reader :body
5
+
6
+ ##
7
+ # Downloads remote file from Google Drive with given mime_type
8
+ #
9
+ # @param [FileConvert::Client] client
10
+ # @param [FileConvert::File] remote_file
11
+ # @param [String] mime_type
12
+ # Target mime_type the file gets converted to
13
+ #
14
+ # @return [FileConvert::File] remote_file with requested #conversions
15
+ def initialize(client, remote_file, mime_type)
16
+ @client = client
17
+ @remote_file = remote_file
18
+ @original_file_data = remote_file.data
19
+ @mime_type = mime_type
20
+
21
+ # Raise if requested mime-type is not available
22
+ fail missing_mime_type_exception unless export_links.key?(mime_type)
23
+ fail data_error_exception if @original_file_data.to_hash.key?('error')
24
+
25
+ @file = fetch_file
26
+ @body = @file.body
27
+ @remote_file.add_conversion(mime_type, self)
28
+ end
29
+
30
+ ##
31
+ # Saves result as file
32
+ # @param [String] target_path
33
+ #
34
+ # @return [FileConvert::Conversion]
35
+ def save(target_path)
36
+ ::File.open(target_path, 'w') { |file| file.write(@file.body) }
37
+ end
38
+
39
+ private
40
+
41
+ ##
42
+ # @return [Hash] available mime-type download URIs
43
+ def export_links
44
+ @original_file_data['exportLinks'].to_hash
45
+ end
46
+
47
+ ###
48
+ # Actually downloads the file
49
+ # Raises if request was not successfull
50
+ #
51
+ # @return [Google::APIClient::Result]
52
+ def fetch_file
53
+ @client.execute(uri: export_links[@mime_type]).tap do |result|
54
+ fail connection_error_exception unless result.status == 200
55
+ end
56
+ end
57
+
58
+ def data_error_exception
59
+ Exception::UploadedFileDataError.new(@original_file_data)
60
+ end
61
+
62
+ def missing_mime_type_exception
63
+ Exception::MissingConversionMimeType.new(@mime_type, export_links.keys)
64
+ end
65
+
66
+ def connection_error_exception
67
+ Exception::DownloadConnectionError.new(@file['error']['message'])
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,55 @@
1
+ module FileConvert
2
+ module Exception
3
+ class MissingConversionMimeType < StandardError
4
+ def initialize(requested_mime_type, available_mime_types)
5
+ super()
6
+ @requested_mime_type = requested_mime_type
7
+ @available_mime_types = available_mime_types
8
+ end
9
+
10
+ def message
11
+ ''"
12
+ The requested mime type '#{@requested_mime_type}' is not available.
13
+ Available mime types: #{@available_mime_types.join(', ')}.
14
+ "''
15
+ end
16
+ end
17
+
18
+ class UploadedFileDataError < StandardError
19
+ def initialize(file_data)
20
+ super()
21
+ @file_data = file_data
22
+ end
23
+
24
+ def message
25
+ ''"
26
+ An error occured while uploading the file.
27
+ Data was: #{@file_data}
28
+ "''
29
+ end
30
+ end
31
+
32
+ class DownloadConnectionError < StandardError
33
+ def initialize(error_message)
34
+ super()
35
+ @error_message = error_message
36
+ end
37
+
38
+ def message
39
+ ''"
40
+ An error occured connection to Google Drive.
41
+ Error message was: #{@error_message}
42
+ "''
43
+ end
44
+ end
45
+
46
+ class MissingConfig < StandardError
47
+ def message
48
+ ''"
49
+ Please define a config for FileConvert.
50
+ See https://github.com/tolingo/file-convert#config for default.
51
+ "''
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,30 @@
1
+ module FileConvert
2
+ class File
3
+ attr_reader :original_file
4
+ attr_reader :data
5
+ attr_reader :conversions
6
+
7
+ ##
8
+ # Hold original and conversion
9
+ #
10
+ # @params [File] original_file
11
+ #
12
+ # @return [FileConvert::File]
13
+ def initialize(original_file)
14
+ @original_file = original_file
15
+ @data = original_file.data
16
+ @conversions = {}
17
+ end
18
+
19
+ ##
20
+ # Adds a new conversion
21
+ #
22
+ # @param [String] mime_type
23
+ # @param [File] converted_file
24
+ #
25
+ # @return [FileConvert::File] (self)
26
+ def add_conversion(mime_type, converted_file)
27
+ tap { @conversions[mime_type] = converted_file }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ module FileConvert
2
+ class Upload
3
+ DEFAULT_PARAMS = {
4
+ 'uploadType' => 'multipart',
5
+ 'convert' => true,
6
+ 'alt' => 'json'
7
+ }
8
+
9
+ attr_reader :file
10
+
11
+ ##
12
+ # Uploads file to Google Drive
13
+ #
14
+ # @param [FileConvert::Client] client
15
+ # @param [String] file_path
16
+ # File to upload
17
+ # @param [String] mime_type
18
+ # Source mime_type of upload-file
19
+ #
20
+ # @return [FileConvert::File] New File object without conversions yet
21
+ def initialize(client, file_path, mime_type)
22
+ @client = client
23
+ @file_path = file_path
24
+ @mime_type = mime_type
25
+
26
+ uploaded_file = client.execute(
27
+ api_method: client.drive.files.insert,
28
+ body_object: touch_file,
29
+ media: upload_io,
30
+ parameters: DEFAULT_PARAMS
31
+ )
32
+
33
+ @file = FileConvert::File.new(uploaded_file)
34
+ end
35
+
36
+ private
37
+
38
+ def touch_file
39
+ @client.drive.files.insert.request_schema.new(
40
+ 'title' => SecureRandom.uuid,
41
+ 'description' => 'FileConvert Conversion-File',
42
+ 'mimeType' => @mime_type
43
+ )
44
+ end
45
+
46
+ def upload_io
47
+ Google::APIClient::UploadIO.new(@file_path, @mime_type)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ module FileConvert
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].compact.join('.')
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: file-convert
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Roman Ernst
8
+ - Jan Raasch
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-09-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: google-api-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 0.7.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 0.7.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 3.0.0
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 3.0.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: rubocop
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 0.25.0
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 0.25.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 10.3.2
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 10.3.2
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 0.10.1
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 0.10.1
84
+ - !ruby/object:Gem::Dependency
85
+ name: codeclimate-test-reporter
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: 0.4.0
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 0.4.0
98
+ description: Uses google-api-ruby-client and Google Drive to convert files from one
99
+ mime-type to another
100
+ email:
101
+ - rernst@farbenmeer.net
102
+ - jan@janraasch.com
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - LICENSE
108
+ - README.md
109
+ - lib/file_convert.rb
110
+ - lib/file_convert/client.rb
111
+ - lib/file_convert/configure.rb
112
+ - lib/file_convert/conversion.rb
113
+ - lib/file_convert/exception.rb
114
+ - lib/file_convert/file.rb
115
+ - lib/file_convert/upload.rb
116
+ - lib/file_convert/version.rb
117
+ homepage: https://github.com/tolingo/file-convert
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: 1.9.2
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.2.0.rc.1
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Instrumentalize Google Drive to convert files
141
+ test_files: []