eivid 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +215 -0
  4. data/Rakefile +18 -0
  5. data/app/controllers/eivid/application_controller.rb +20 -0
  6. data/app/controllers/eivid/concerns/video_validations.rb +42 -0
  7. data/app/controllers/eivid/videos_controller.rb +48 -0
  8. data/app/dump/eivid/video_mime_dump.rb +9 -0
  9. data/app/errors/eivid/incorrect_video_mime_type_error.rb +4 -0
  10. data/app/errors/eivid/main_app_record_not_found_error.rb +4 -0
  11. data/app/errors/eivid/maximum_vimeo_poll_reached_error.rb +4 -0
  12. data/app/errors/eivid/video_file_not_present_error.rb +4 -0
  13. data/app/errors/eivid/video_file_size_too_big_error.rb +4 -0
  14. data/app/errors/eivid/video_unavailable_error.rb +4 -0
  15. data/app/errors/eivid/video_urls_unavailable_error.rb +4 -0
  16. data/app/jobs/eivid/application_job.rb +4 -0
  17. data/app/jobs/eivid/check_vimeo_status_job.rb +46 -0
  18. data/app/jobs/eivid/get_vimeo_urls_job.rb +62 -0
  19. data/app/jobs/eivid/upload_vimeo_job.rb +55 -0
  20. data/app/mailers/eivid/application_mailer.rb +6 -0
  21. data/app/models/eivid/application_record.rb +5 -0
  22. data/app/models/eivid/concerns/main_app/owner.rb +17 -0
  23. data/app/models/eivid/concerns/main_app/user.rb +11 -0
  24. data/app/models/eivid/concerns/main_app/video_concerns.rb +16 -0
  25. data/app/models/eivid/concerns/main_app/video_resource.rb +11 -0
  26. data/app/models/eivid/concerns/request_service/delete_video.rb +17 -0
  27. data/app/models/eivid/concerns/request_service/get_video.rb +9 -0
  28. data/app/models/eivid/concerns/request_service/manage_folder.rb +29 -0
  29. data/app/models/eivid/concerns/request_service/poll_status.rb +9 -0
  30. data/app/models/eivid/concerns/request_service/testing_methods.rb +38 -0
  31. data/app/models/eivid/concerns/request_service/upload_video.rb +31 -0
  32. data/app/models/eivid/owner.rb +21 -0
  33. data/app/models/eivid/video.rb +21 -0
  34. data/app/models/eivid/video_resource.rb +8 -0
  35. data/app/services/eivid/notify_front_service.rb +14 -0
  36. data/app/services/eivid/request_service.rb +42 -0
  37. data/app/services/eivid/upload_service.rb +30 -0
  38. data/config/initializers/macro_initializer.rb +22 -0
  39. data/config/routes.rb +8 -0
  40. data/db/migrate/20210325114212_create_eivid_videos.rb +11 -0
  41. data/db/migrate/20210325140804_add_uploaded_bool_to_videos.rb +5 -0
  42. data/db/migrate/20210330092643_create_eivid_owners.rb +9 -0
  43. data/db/migrate/20210330094604_add_external_id_to_owner.rb +5 -0
  44. data/db/migrate/20210330100147_add_folder_id_to_owner.rb +5 -0
  45. data/db/migrate/20210330103729_add_vimeo_id_to_videos.rb +5 -0
  46. data/db/migrate/20210331082454_add_status_poll_cnt_to_videos.rb +5 -0
  47. data/db/migrate/20210401091448_create_eivid_video_resources.rb +12 -0
  48. data/db/migrate/20210401123512_remove_status_poll_cnt_from_eivid_videos.rb +5 -0
  49. data/db/migrate/20210401132759_create_eivid_dev_envs.rb +11 -0
  50. data/db/migrate/20210401134700_drop.rb +5 -0
  51. data/db/migrate/20210419122001_change_url_to_embedded_url.rb +5 -0
  52. data/db/migrate/20210419122752_add_video_urls_to_videos.rb +7 -0
  53. data/db/migrate/20210420120017_add_user_id_to_eivid_videos.rb +5 -0
  54. data/lib/eivid.rb +6 -0
  55. data/lib/eivid/engine.rb +33 -0
  56. data/lib/eivid/version.rb +3 -0
  57. data/lib/tasks/eivid_tasks.rake +4 -0
  58. metadata +144 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 98674e7ecdf813a76dda68ec8f37ad5a1ba3bee64c3c480d50b8f4d5f2cee8b1
4
+ data.tar.gz: 3371b018b813ad3abde17f2ec6e5843d71227c98b1eff1fc8606bdd77863979e
5
+ SHA512:
6
+ metadata.gz: c631a4883bd2318cd4ee1da40344e45e9b30158225f69187ca5bb14c3389d2fca39f1481ed0911ed35acc9a3892ec9058ae33b88a27213fbe6c41e9f43fca1f8
7
+ data.tar.gz: f2f2d8e6ffcdec2242614f2cf86ac9f1ef45738d525912f919757b3a9d99b222c6c8a26e7c2a5d25404b13e04be8dd17ad7704bf49f45c6e2620f3681a85d03b
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2021 Jurriaan Schrofer
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.md ADDED
@@ -0,0 +1,215 @@
1
+ # Eivid
2
+
3
+ Never stops streaming awesome videos, yay!
4
+
5
+
6
+
7
+ ## Installation
8
+
9
+ Add the following to your application's Gemfile and run $bundle:
10
+
11
+ ```ruby
12
+
13
+ gem 'eivid', git: 'https://github.com/eitje-app/eivid_engine', branch: 'production'
14
+
15
+ ```
16
+ Or, for development purposes, add instead:
17
+
18
+ ```ruby
19
+ local_eivid_path = "/Users/jurriaanschrofer/Documents/eivid"
20
+ if ENV["RAILS_ENV"] == 'development' && Dir.glob(local_eivid_path).any?
21
+ gem 'eivid', path: local_eivid_path
22
+ else
23
+ gem 'eivid', git: 'https://github.com/eitje-app/eivid_engine', branch: 'production'
24
+ end
25
+ ```
26
+
27
+ Add the following file to your app's config/initializers directory:
28
+
29
+ ```ruby
30
+
31
+ # eivid.rb
32
+
33
+ Eivid.set_mattr_accessors do |config|
34
+ config.owner_model = "owner"
35
+ end
36
+
37
+ ```
38
+
39
+ In this file, set the {owner_model} to your apps owner of videos, which generates the following methods (in this example config.owner_model is set to "organisation"):
40
+
41
+ ```ruby
42
+
43
+ # retrieves the owner_id from a record
44
+ Eivid::Video.first.organisation_id
45
+
46
+ # returns the owner record of your application
47
+ Eivid::Video.first.organisation
48
+
49
+ # scope, which returns all records for your application's organisation
50
+ Eivid::Video.of_organisation(id)
51
+
52
+ # returns the owner record of your application
53
+ Eivid::Owner.organisation
54
+
55
+ ```
56
+
57
+
58
+
59
+ ## Setup
60
+
61
+ Create and run the required migrations:
62
+
63
+ ```bash
64
+
65
+ $ rails eivid:install:migrations
66
+ $ rails db:migrate
67
+
68
+ ```
69
+
70
+ For your application's owner model (in this example Organisation), run the following command, which creates all dedicated folders within Vimeo:
71
+
72
+ ```ruby
73
+
74
+ Organisation.find_each { |owner| Eivid::Owner.create(external_id: owner.id) }
75
+
76
+ ```
77
+
78
+ Add the following to your routes.rb:
79
+
80
+ ```ruby
81
+
82
+ mount Eivid::Engine => "/eivid"
83
+
84
+ ```
85
+
86
+ Set the following environment variables in your application:
87
+
88
+ ```ruby
89
+
90
+ VIMEO_ACCESS_TOKEN
91
+
92
+ ```
93
+
94
+
95
+
96
+ ## Include Owner
97
+
98
+ Witin your application's owner model (in this example Organisation), add to following:
99
+
100
+ ```ruby
101
+
102
+ eivid_owner
103
+
104
+ ```
105
+
106
+ Which runs an after_create effect, which creates an Eivid::Owner for every new Organisation record, and generates the following methods within your application:
107
+
108
+ ```ruby
109
+
110
+ # returns a single Eivid::Owner record for the owner, which includes a Vimeo folder_id
111
+ Organisation.first.video_owner
112
+
113
+ #returns all Eivid::Video records, which each contain an url to the video and vimeo_id
114
+ Organisation.first.videos
115
+
116
+ ```
117
+
118
+
119
+
120
+ ## Include VideoResource
121
+
122
+ Besides an owner, an Eivid::Video can belongs to many resources of your main application, e.g. a Post, Manual or Message. This functionality is provided through a join table Eivid::VideoResource, which enables any model of your application to has_many Eivid::VideoResource. In order to create this association, paste the following code in your application's resource holder:
123
+
124
+ ```ruby
125
+
126
+ eivid_video_resource
127
+
128
+ ```
129
+
130
+ Which generates the following methods within your application (in this example for a Post model):
131
+
132
+ ```ruby
133
+
134
+ # returns join table records
135
+ Post.first.video_resources
136
+
137
+ # returns video records
138
+ Post.first.videos
139
+
140
+ # scope which returns all records (here Post instances) which have a video
141
+ Post.has_video
142
+
143
+ # scope which returns all records (here Post instances) which do not have a video
144
+ Post.has_not_video
145
+
146
+ ```
147
+
148
+
149
+
150
+ ## Include User
151
+
152
+ An Eivid::Video can optionally belong to your application's User model. If you want to hook up your User with Eivid::Video, include the following in your user.rb file.
153
+
154
+ Note: for the user_id to be added to a Eivid::Video record, your main application should provide an User instance @user within your controllers.
155
+
156
+ ```ruby
157
+
158
+ eivid_user
159
+
160
+ ```
161
+
162
+ Which generates the following methods within your application:
163
+
164
+ ```ruby
165
+
166
+ # returns video records
167
+ User.first.videos
168
+
169
+ # returns join table records
170
+ User.first.video_resources
171
+
172
+ # returns an User instance
173
+ Eivid::Video.first.user
174
+
175
+ ```
176
+
177
+
178
+
179
+
180
+
181
+ ## Optional Config: Set Controller before_action
182
+
183
+ Before each controller action, the the @owner variable is set through through ```params['external_owner_id']```. If you want to overwrite this logic, because your main application already has some kind of standardized before hooks, you can do that by setting the following in your config/initializers/eivid.rb file. This code will be evaluated, instead of ```params['external_owner_id']```.
184
+
185
+ ```ruby
186
+
187
+ Eivid.set_mattr_accessors do |config|
188
+ config.infer_external_owner_id = "@env.organisation.id"
189
+ end
190
+
191
+ ```
192
+
193
+
194
+
195
+ ## Optional Config: Set Front End Notifications
196
+
197
+ If you want your front end to be notified on the progress of the videos being uploaded to vimeo, you can add the following to your eivid.rb config file. The method fields should be any proc and accept a single positional hash as argument, which stores all the progress information. This proc will be called on any progress change, thus enabbles you to set which method in your main application should handle the change.
198
+
199
+ ```ruby
200
+
201
+ # eivid.rb
202
+
203
+ Eivid.set_mattr_accessors do |config|
204
+ config.notify_front_enabled = true
205
+ config.notify_method_on_upload = -> (data) { "NotifyFrontOnVimeoService.progress(#{data})" }
206
+ config.notify_method_on_video_available = -> (data) { "NotifyFrontOnVimeoService.progress(#{data})" }
207
+ config.notify_method_on_versions_available = -> (data) { "NotifyFrontOnVimeoService.progress(#{data})" }
208
+ end
209
+
210
+ ```
211
+
212
+
213
+
214
+
215
+
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
9
+
10
+ require "rake/testtask"
11
+
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'test'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = false
16
+ end
17
+
18
+ task default: :test
@@ -0,0 +1,20 @@
1
+ module Eivid
2
+ class ApplicationController < API::BaseController
3
+
4
+ include Concerns::VideoValidations
5
+
6
+ private
7
+
8
+ def set_owner
9
+ @owner = Owner.find_by(external_id: eval(Eivid.infer_external_owner_id)) || report_record_not_found
10
+ end
11
+
12
+ def report_record_not_found
13
+ raise MainAppRecordNotFoundError.new(
14
+ "The given external_owner_id could not be mapped to your application's owner records.
15
+ Beware: if you have overwritten the Eivid.infer_external_owner_id setting, the error is dependant on your main application."
16
+ )
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ module Eivid::Concerns::VideoValidations
2
+ extend ActiveSupport::Concern
3
+ included do
4
+
5
+ MAX_MB_VIDEO = 100
6
+
7
+ private
8
+
9
+ def validate_video_file
10
+ validate_video_file_presence
11
+ validate_video_file_format
12
+ validate_video_file_size
13
+ end
14
+
15
+ def validate_video_file_presence
16
+ unless params["video_file"]
17
+ raise Eivid::VideoFileNotPresentError.new(
18
+ "you forgot to add a required 'video_file' to your request"
19
+ )
20
+ end
21
+ end
22
+
23
+ def validate_video_file_format
24
+ mime = params["video_file"]&.original_filename&.split('.')&.last&.downcase
25
+ unless Eivid::VideoMimeDump::DATA.include?(mime)
26
+ raise Eivid::IncorrectVideoMimeTypeError.new(
27
+ "the 'video_file' you tried to upload, is of an invalid mime type"
28
+ )
29
+ end
30
+ end
31
+
32
+ def validate_video_file_size
33
+ megabytes = params["video_file"].tempfile.size / 1.0.megabyte
34
+ unless MAX_MB_VIDEO >= megabytes
35
+ raise VideoFileSizeTooBigError.new(
36
+ "the 'video_file' size (#{megabytes.round(2)} mb) you tried to upload exceeds the maximum file size (#{MAX_MB_VIDEO} mb)"
37
+ )
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,48 @@
1
+ require_dependency "eivid/application_controller"
2
+ require 'tempfile'
3
+
4
+ # for local development, run:
5
+ # QUEUE=* rake resque:work
6
+ # rake environment resque:scheduler
7
+
8
+ module Eivid
9
+ class VideosController < ApplicationController
10
+
11
+ before_action :set_owner, only: [:upload_video, :owner_videos]
12
+ before_action :set_video, only: [:show, :destroy]
13
+ before_action :validate_video_file, only: [:upload_video]
14
+
15
+ def upload_video
16
+ record = UploadService.upload(owner: @owner, user: @user, video_file: video_params["video_file"])
17
+ render json: record
18
+ end
19
+
20
+ def owner_videos
21
+ render json: @owner.videos
22
+ end
23
+
24
+ def index
25
+ render json: Video.all
26
+ end
27
+
28
+ def show
29
+ render json: @video
30
+ end
31
+
32
+ def destroy
33
+ record = RequestService.destroy(video: @video)
34
+ render json: record
35
+ end
36
+
37
+ private
38
+
39
+ def set_video
40
+ @video = Video.find params["id"]
41
+ end
42
+
43
+ def video_params
44
+ params.permit("video_file")
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ module Eivid::VideoMimeDump
2
+
3
+ DATA = %w$
4
+ wemb mkv flv vob ogv ogg drc gif gifv mng avi mts m2ts ts mov qt wmv yuv rm rmvb
5
+ viv asf amv mp4 m4p m4v mpg mp2 mmpeg mpe mpv m2v m4v svi 3gp 3g2 mxf roq nsv flv
6
+ f4v f4p f4a f4b
7
+ $
8
+
9
+ end
@@ -0,0 +1,4 @@
1
+ module Eivid
2
+ class IncorrectVideoMimeTypeError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eivid
2
+ class MainAppRecordNotFoundError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eivid
2
+ class MaximumVimeoPollReachedError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eivid
2
+ class VideoFileNotPresentError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eivid
2
+ class VideoFileSizeTooBigError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eivid
2
+ class VideoUnavailableError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eivid
2
+ class VideoUrlsUnavailableError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Eivid
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,46 @@
1
+ module Eivid
2
+ class CheckVimeoStatusJob < ApplicationJob
3
+
4
+ retry_on VideoUnavailableError, wait: 10.seconds, attempts: 50
5
+ after_perform :poll_vimeo_urls
6
+
7
+ def perform(video_record:)
8
+ @video_record = video_record
9
+
10
+ set_vimeo_id
11
+ set_video_status
12
+
13
+ upload_completed ? notify_front : (raise Eivid::VideoUnavailableError)
14
+ end
15
+
16
+ private
17
+
18
+ def set_vimeo_id
19
+ @vimeo_id ||= @video_record.url_embedded.split('/').last
20
+ end
21
+
22
+ def set_video_status
23
+ @video_status = Eivid::RequestService.get_status(vimeo_id: @vimeo_id)["status"]
24
+ end
25
+
26
+ def upload_completed
27
+ @video_status == "available"
28
+ end
29
+
30
+ def notify_front
31
+ data = { video: @video_record.slice(:id, :user_id), progress: { percentage: 66, step: "The video is available on Vimeo." } }
32
+ NotifyFrontService.progress('notify_method_on_video_available', data)
33
+ end
34
+
35
+ def report_max_poll
36
+ raise MaximumVimeoPollReachedError.new (
37
+ "the maximum amount of polling Vimeo (#{@@maximum_vimeo_polls} times) for the status of Eivid::Video ##{@video_record&.id} is reached."
38
+ )
39
+ end
40
+
41
+ def poll_vimeo_urls
42
+ GetVimeoUrlsJob.perform_later(video_record: @video_record, vimeo_id: @vimeo_id)
43
+ end
44
+
45
+ end
46
+ end