biovision 0.0.200518.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.
Files changed (170) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +214 -0
  4. data/Rakefile +22 -0
  5. data/app/assets/config/biovision_manifest.js +1 -0
  6. data/app/assets/images/biovision/components/carousel/arrow-left.svg +4 -0
  7. data/app/assets/images/biovision/components/carousel/arrow-right.svg +4 -0
  8. data/app/assets/images/biovision/icons/breadcrumb-hover.svg +1 -0
  9. data/app/assets/images/biovision/icons/breadcrumb.svg +1 -0
  10. data/app/assets/images/biovision/icons/components/contact.svg +26 -0
  11. data/app/assets/images/biovision/icons/components/content.svg +20 -0
  12. data/app/assets/images/biovision/icons/components/users.svg +21 -0
  13. data/app/assets/images/biovision/icons/key.svg +16 -0
  14. data/app/assets/images/biovision/icons/log_in.svg +15 -0
  15. data/app/assets/images/biovision/icons/log_out.svg +15 -0
  16. data/app/assets/images/biovision/icons/messages/error.svg +14 -0
  17. data/app/assets/images/biovision/icons/messages/info.svg +8 -0
  18. data/app/assets/images/biovision/icons/messages/success.svg +12 -0
  19. data/app/assets/images/biovision/icons/messages/warning.svg +13 -0
  20. data/app/assets/images/biovision/icons/settings.svg +41 -0
  21. data/app/assets/images/biovision/placeholders/16x9.svg +11 -0
  22. data/app/assets/images/biovision/placeholders/1x1.svg +11 -0
  23. data/app/assets/images/biovision/placeholders/3x2.svg +11 -0
  24. data/app/assets/images/biovision/placeholders/user.svg +15 -0
  25. data/app/assets/stylesheets/biovision/admin.scss +6 -0
  26. data/app/assets/stylesheets/biovision/admin/components.scss +59 -0
  27. data/app/assets/stylesheets/biovision/admin/default.scss +57 -0
  28. data/app/assets/stylesheets/biovision/admin/layout.scss +95 -0
  29. data/app/assets/stylesheets/biovision/admin/vars.scss +56 -0
  30. data/app/assets/stylesheets/biovision/biovision.scss +134 -0
  31. data/app/assets/stylesheets/biovision/biovision/messages.scss +41 -0
  32. data/app/assets/stylesheets/biovision/components/carousel.scss +53 -0
  33. data/app/assets/stylesheets/biovision/components/forms.scss +85 -0
  34. data/app/assets/stylesheets/biovision/components/hamburger.scss +56 -0
  35. data/app/assets/stylesheets/biovision/components/lists.scss +91 -0
  36. data/app/assets/stylesheets/biovision/default.scss +57 -0
  37. data/app/assets/stylesheets/biovision/themes/default_theme.scss +2 -0
  38. data/app/assets/stylesheets/biovision/themes/default_theme/components.scss +3 -0
  39. data/app/assets/stylesheets/biovision/themes/default_theme/layout.scss +44 -0
  40. data/app/assets/stylesheets/biovision/themes/default_theme/layout/footer.scss +0 -0
  41. data/app/assets/stylesheets/biovision/themes/default_theme/layout/header.scss +39 -0
  42. data/app/assets/stylesheets/biovision/vars.scss +53 -0
  43. data/app/controllers/admin/agents_controller.rb +15 -0
  44. data/app/controllers/admin/components_controller.rb +174 -0
  45. data/app/controllers/admin/index_controller.rb +11 -0
  46. data/app/controllers/admin/ip_addresses_controller.rb +15 -0
  47. data/app/controllers/admin_controller.rb +14 -0
  48. data/app/controllers/authentication_controller.rb +79 -0
  49. data/app/controllers/concerns/authentication.rb +45 -0
  50. data/app/controllers/index_controller.rb +8 -0
  51. data/app/controllers/my/confirmations_controller.rb +2 -0
  52. data/app/controllers/my/index_controller.rb +8 -0
  53. data/app/controllers/my/profiles_controller.rb +128 -0
  54. data/app/controllers/my/recoveries_controller.rb +2 -0
  55. data/app/helpers/biovision_components_helper.rb +14 -0
  56. data/app/helpers/users_helper.rb +11 -0
  57. data/app/lib/biovision/components/base_component.rb +177 -0
  58. data/app/lib/biovision/components/component_settings.rb +30 -0
  59. data/app/lib/biovision/components/privilege_handler.rb +77 -0
  60. data/app/lib/biovision/components/track_component.rb +9 -0
  61. data/app/lib/biovision/components/users/authentication.rb +47 -0
  62. data/app/lib/biovision/components/users/code_handler.rb +23 -0
  63. data/app/lib/biovision/components/users/profile_handler.rb +12 -0
  64. data/app/lib/biovision/components/users/registration_handler.rb +99 -0
  65. data/app/lib/biovision/components/users_component.rb +47 -0
  66. data/app/lib/biovision/notifiers/base_notifier.rb +69 -0
  67. data/app/lib/biovision/notifiers/socialization_notifier.rb +31 -0
  68. data/app/lib/biovision/notifiers/users_notifier.rb +15 -0
  69. data/app/models/agent.rb +35 -0
  70. data/app/models/biovision_component.rb +45 -0
  71. data/app/models/biovision_component_user.rb +21 -0
  72. data/app/models/browser.rb +34 -0
  73. data/app/models/code.rb +71 -0
  74. data/app/models/concerns/checkable.rb +22 -0
  75. data/app/models/concerns/flat_priority.rb +50 -0
  76. data/app/models/concerns/has_language.rb +10 -0
  77. data/app/models/concerns/has_owner.rb +22 -0
  78. data/app/models/concerns/has_simple_image.rb +18 -0
  79. data/app/models/concerns/has_track.rb +10 -0
  80. data/app/models/concerns/has_uuid.rb +12 -0
  81. data/app/models/concerns/meta_texts.rb +16 -0
  82. data/app/models/concerns/nested_priority.rb +58 -0
  83. data/app/models/concerns/required_unique_name.rb +16 -0
  84. data/app/models/concerns/required_unique_slug.rb +15 -0
  85. data/app/models/concerns/toggleable.rb +33 -0
  86. data/app/models/foreign_site.rb +34 -0
  87. data/app/models/foreign_user.rb +21 -0
  88. data/app/models/ip_address.rb +31 -0
  89. data/app/models/language.rb +31 -0
  90. data/app/models/login_attempt.rb +35 -0
  91. data/app/models/metric.rb +48 -0
  92. data/app/models/metric_value.rb +11 -0
  93. data/app/models/notification.rb +37 -0
  94. data/app/models/simple_image.rb +47 -0
  95. data/app/models/simple_image_tag.rb +30 -0
  96. data/app/models/simple_image_tag_image.rb +13 -0
  97. data/app/models/token.rb +96 -0
  98. data/app/models/user.rb +136 -0
  99. data/app/models/user_language.rb +15 -0
  100. data/app/uploaders/simple_image_uploader.rb +96 -0
  101. data/app/uploaders/user_image_uploader.rb +58 -0
  102. data/app/views/admin/agents/_nav_item.html.erb +6 -0
  103. data/app/views/admin/agents/entity/_in_list.html.erb +6 -0
  104. data/app/views/admin/agents/index.html.erb +13 -0
  105. data/app/views/admin/components/_list.html.erb +12 -0
  106. data/app/views/admin/components/entity/_links.html.erb +35 -0
  107. data/app/views/admin/components/entity/_section.html.erb +12 -0
  108. data/app/views/admin/components/index.html.erb +12 -0
  109. data/app/views/admin/components/links/_track.html.erb +2 -0
  110. data/app/views/admin/components/links/_users.html.erb +11 -0
  111. data/app/views/admin/components/privileges.html.erb +20 -0
  112. data/app/views/admin/components/privileges/_component_user.html.erb +17 -0
  113. data/app/views/admin/components/privileges/_links.html.erb +35 -0
  114. data/app/views/admin/components/privileges/_privilege_flag.html.erb +28 -0
  115. data/app/views/admin/components/privileges/_users.html.erb +23 -0
  116. data/app/views/admin/components/settings.html.erb +39 -0
  117. data/app/views/admin/components/settings/_new_parameter.html.erb +46 -0
  118. data/app/views/admin/components/settings/_parameters.html.erb +20 -0
  119. data/app/views/admin/components/settings/_setting.html.erb +18 -0
  120. data/app/views/admin/components/settings/_settings.html.erb +31 -0
  121. data/app/views/admin/components/show.html.erb +14 -0
  122. data/app/views/admin/index/index.html.erb +14 -0
  123. data/app/views/admin/ip_addresses/_nav_item.html.erb +6 -0
  124. data/app/views/admin/ip_addresses/entity/_in_list.html.erb +6 -0
  125. data/app/views/admin/ip_addresses/index.html.erb +13 -0
  126. data/app/views/admin/unauthorized.html.erb +19 -0
  127. data/app/views/authentication/_form.html.erb +40 -0
  128. data/app/views/authentication/failed.js.erb +3 -0
  129. data/app/views/authentication/new.html.erb +21 -0
  130. data/app/views/index/index.html.erb +0 -0
  131. data/app/views/layouts/admin.html.erb +23 -0
  132. data/app/views/layouts/admin/_breadcrumbs.html.erb +8 -0
  133. data/app/views/layouts/admin/_footer.html.erb +10 -0
  134. data/app/views/layouts/admin/_header.html.erb +18 -0
  135. data/app/views/layouts/admin/header/_logo.html.erb +3 -0
  136. data/app/views/layouts/application/_footer.html.erb +8 -0
  137. data/app/views/layouts/application/_header.html.erb +9 -0
  138. data/app/views/layouts/application/header/_authentication.html.erb +13 -0
  139. data/app/views/my/index/index.html.erb +0 -0
  140. data/app/views/my/profiles/closed.html.erb +12 -0
  141. data/app/views/my/profiles/new.html.erb +17 -0
  142. data/app/views/my/profiles/new/_form.html.erb +147 -0
  143. data/app/views/shared/_breadcrumbs.html.erb +8 -0
  144. data/app/views/shared/_cookie_notification.html.erb +4 -0
  145. data/app/views/shared/_flash_messages.html.erb +7 -0
  146. data/app/views/shared/_meta_texts.html.erb +31 -0
  147. data/app/views/shared/_nothing_found.html.erb +1 -0
  148. data/app/views/shared/_pagination.jbuilder +15 -0
  149. data/app/views/shared/admin/_list.html.erb +19 -0
  150. data/app/views/shared/admin/_list_with_priority.html.erb +19 -0
  151. data/app/views/shared/admin/_toggleable.html.erb +8 -0
  152. data/app/views/shared/entity/_list_of_errors.html.erb +7 -0
  153. data/app/views/shared/forms/errors.js.erb +5 -0
  154. data/config/initializers/carrierwave.rb +27 -0
  155. data/config/initializers/pluralization.rb +2 -0
  156. data/config/locales/biovision-ru.yml +90 -0
  157. data/config/locales/components-ru.yml +81 -0
  158. data/config/locales/track-ru.yml +40 -0
  159. data/config/locales/users-ru.yml +130 -0
  160. data/config/routes.rb +75 -0
  161. data/db/migrate/20191228000000_create_biovision_components.rb +72 -0
  162. data/db/migrate/20200224000000_create_track_component.rb +59 -0
  163. data/db/migrate/20200224000010_create_users_component.rb +189 -0
  164. data/db/migrate/20200404000000_create_simple_images.rb +54 -0
  165. data/lib/biovision.rb +9 -0
  166. data/lib/biovision/base_methods.rb +167 -0
  167. data/lib/biovision/engine.rb +40 -0
  168. data/lib/biovision/version.rb +5 -0
  169. data/lib/tasks/biovision_tasks.rake +4 -0
  170. metadata +392 -0
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Component notification for user
4
+ #
5
+ # Attributes:
6
+ # biovision_component_id [BiovisionComponent]
7
+ # created_at [DateTime]
8
+ # data [jsonb]
9
+ # email_sent [boolean]
10
+ # read [boolean]
11
+ # updated_at [DateTime]
12
+ # user_id [User]
13
+ # uuid [uuid]
14
+ class Notification < ApplicationRecord
15
+ include HasOwner
16
+ include HasUuid
17
+
18
+ belongs_to :biovision_component
19
+ belongs_to :user
20
+
21
+ scope :recent, -> { order('id desc') }
22
+ scope :unread, -> { where(read: false) }
23
+ scope :not_sent, -> { where(email_sent: false) }
24
+ scope :data_id, ->(v) { where("cast(data->>'id' as integer) = ?", v) }
25
+ scope :data_type, ->(v) { where("data->>'type' = ?", v) }
26
+ scope :list_for_owner, ->(v) { owned_by(v).recent }
27
+
28
+ # @param [User] user
29
+ # @param [Integer] page
30
+ def self.page_for_owner(user, page = 1)
31
+ list_for_owner(user).page(page)
32
+ end
33
+
34
+ def component_slug
35
+ biovision_component.slug
36
+ end
37
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Universal simple image
4
+ #
5
+ # Attributes:
6
+ # agent_id [Agent], optional
7
+ # biovision_component_id [BiovisionComponent]
8
+ # caption [string], optional
9
+ # created_at [DateTime]
10
+ # image [SimpleImageUploader]
11
+ # image_alt_text [string]
12
+ # ip_address_id [IpAddress], optional
13
+ # object_count [integer]
14
+ # source_link [string], optional
15
+ # source_name [string], optional
16
+ # updated_at [DateTime]
17
+ # user_id [User], optional
18
+ # uuid [uuid]
19
+ # data [jsonb]
20
+ class SimpleImage < ApplicationRecord
21
+ include Checkable
22
+ include HasOwner
23
+ include HasTrack
24
+ include HasUuid
25
+
26
+ CAPTION_LIMIT = 255
27
+ LINK_LIMIT = 255
28
+ NAME_LIMIT = 255
29
+ META_LIMIT = 255
30
+
31
+ belongs_to :biovision_component
32
+ belongs_to :user, optional: true
33
+
34
+ validates_presence_of :image
35
+ validates_length_of :caption, maximum: CAPTION_LIMIT
36
+ validates_length_of :image_alt_text, maximum: META_LIMIT
37
+ validates_length_of :source_link, maximum: LINK_LIMIT
38
+ validates_length_of :source_name, maximum: NAME_LIMIT
39
+
40
+ def self.entity_parameters
41
+ %i[caption image image_alt_text source_link source_name]
42
+ end
43
+
44
+ def name
45
+ caption.blank? ? File.basename(image.path) : caption
46
+ end
47
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for simple image
4
+ #
5
+ # Attributes:
6
+ # created_at [DateTime]
7
+ # name [string]
8
+ # simple_images_count [integer]
9
+ # updated_at [DateTime]
10
+ class SimpleImageTag < ApplicationRecord
11
+ include Checkable
12
+ NAME_LIMIT = 100
13
+
14
+ has_many :simple_image_tag_images, dependent: :delete_all
15
+
16
+ before_validation :normalize_name
17
+ validates_uniqueness_of :name, case_sensitive: false
18
+
19
+ scope :list_for_administration, -> { order('name asc') }
20
+
21
+ def self.entity_parameters
22
+ %i[name]
23
+ end
24
+
25
+ private
26
+
27
+ def normalize_name
28
+ self.name = name.to_s[0..NAME_LIMIT]
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Link between simple image and tag
4
+ #
5
+ # Attributes:
6
+ # simple_image_id [SimpleImage]
7
+ # simple_image_tag_id [SimpleImageTag]
8
+ class SimpleImageTagImage < ApplicationRecord
9
+ belongs_to :simple_image
10
+ belongs_to :simple_image_tag, counter_cache: :simple_images_count
11
+
12
+ validates_uniqueness_of :simple_image_tag_id, scope: :simple_image_id
13
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Authentication token
4
+ #
5
+ # Attributes:
6
+ # active [boolean]
7
+ # agent_id [Agent], optional
8
+ # created_at [DateTime]
9
+ # ip_address_id [IpAddress], optional
10
+ # last_used [datetime]
11
+ # updated_at [DateTime]
12
+ # user_id [User]
13
+ # token [string]
14
+ class Token < ApplicationRecord
15
+ include Checkable
16
+ include HasOwner
17
+ include HasTrack
18
+ include Toggleable
19
+
20
+ TOKEN_LIMIT = 255
21
+
22
+ toggleable :active
23
+
24
+ has_secure_token
25
+
26
+ belongs_to :user
27
+ validates_uniqueness_of :token
28
+ validates_length_of :token, maximum: TOKEN_LIMIT
29
+
30
+ scope :recent, -> { order('last_used desc nulls last') }
31
+ scope :active, ->(f) { where(active: f.to_i.positive?) unless f.blank? }
32
+ scope :filtered, ->(f) { with_user_id(f[:user_id]).active(f[:active]) }
33
+ scope :list_for_administration, -> { recent }
34
+ scope :list_for_owner, ->(u) { owned_by(u).recent }
35
+
36
+ # @param [Integer] page
37
+ # @param [Hash] filter
38
+ def self.page_for_administration(page = 1, filter = {})
39
+ filtered(filter).list_for_administration.page(page)
40
+ end
41
+
42
+ # @param [User] user
43
+ # @param [Integer] page
44
+ def self.page_for_owner(user, page = 1)
45
+ list_for_owner(user).page(page)
46
+ end
47
+
48
+ def self.entity_parameters
49
+ %i[active]
50
+ end
51
+
52
+ def self.creation_parameters
53
+ entity_parameters + %i[user_id]
54
+ end
55
+
56
+ # @param [String] input
57
+ def self.[](input)
58
+ find_by(token: input.to_s.split(':')[1].to_s)
59
+ end
60
+
61
+ # @param [String] input
62
+ # @param [Boolean] touch_user
63
+ def self.user_by_token(input, touch_user = false)
64
+ return if input.blank?
65
+
66
+ pair = input.split(':')
67
+ user_by_pair(pair[0], pair[1], touch_user)
68
+ end
69
+
70
+ # @param [Integer] user_id
71
+ # @param [String] token
72
+ # @param [Boolean] touch_user
73
+ def self.user_by_pair(user_id, token, touch_user = false)
74
+ instance = find_by(user_id: user_id, token: token, active: true)
75
+ return if instance.nil?
76
+
77
+ instance.update_columns(last_used: Time.now)
78
+ instance.user.update_columns(last_seen: Time.now) if touch_user
79
+ instance.user
80
+ end
81
+
82
+ def name
83
+ "[#{id}] #{user.profile_name}"
84
+ end
85
+
86
+ # @param [User] user
87
+ def editable_by?(user)
88
+ return true if owned_by?(user)
89
+
90
+ Biovision::Components::UsersComponent[user].allow?('edit')
91
+ end
92
+
93
+ def cookie_pair
94
+ "#{user_id}:#{token}"
95
+ end
96
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ # User
4
+ #
5
+ # Attributes:
6
+ # agent_id [Agent], optional
7
+ # allow_mail [boolean]
8
+ # balance [integer]
9
+ # banned [boolean]
10
+ # birthday [date], optional
11
+ # bot [boolean]
12
+ # consent [boolean]
13
+ # created_at [DateTime]
14
+ # data [jsonb]
15
+ # deleted [boolean]
16
+ # email [string], optional
17
+ # email_confirmed [boolean]
18
+ # image [UserImageUploader]
19
+ # inviter_id [User], optional
20
+ # ip_address_id [IpAddress], optional
21
+ # language_id [Language], optional
22
+ # last_seen [datetime], optional
23
+ # notice [string], optional
24
+ # password_digest [string]
25
+ # phone_confirmed [boolean]
26
+ # primary_id [User], optional
27
+ # screen_name [string]
28
+ # slug [string]
29
+ # super_user [boolean]
30
+ # phone [string], optional
31
+ # referral_link [string]
32
+ # updated_at [DateTime]
33
+ # uuid [uuid]
34
+ class User < ApplicationRecord
35
+ include Checkable
36
+ include HasLanguage
37
+ include HasSimpleImage
38
+ include HasTrack
39
+ include HasUuid
40
+ include Toggleable
41
+
42
+ EMAIL_LIMIT = 250
43
+ EMAIL_PATTERN = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z0-9][-a-z0-9]+)\z/i.freeze
44
+ NOTICE_LIMIT = 255
45
+ PHONE_LIMIT = 50
46
+ SLUG_LIMIT = 250
47
+
48
+ toggleable :banned, :allow_mail, :email_confirmed, :phone_confirmed
49
+
50
+ has_secure_password
51
+ mount_uploader :image, UserImageUploader
52
+
53
+ belongs_to :inviter, class_name: User.to_s, optional: true
54
+ has_many :invitees, class_name: User.to_s, foreign_key: :inviter_id, dependent: :nullify
55
+ has_many :tokens, dependent: :delete_all
56
+ has_many :codes, dependent: :delete_all
57
+ has_many :foreign_users, dependent: :delete_all
58
+ has_many :login_attempts, dependent: :delete_all
59
+ has_many :user_languages, dependent: :delete_all
60
+
61
+ before_validation :normalize_slug
62
+
63
+ validates_acceptance_of :consent
64
+ validates_presence_of :screen_name
65
+ validates_format_of :email, with: EMAIL_PATTERN, allow_blank: true
66
+ validates :screen_name, uniqueness: { case_sensitive: false }
67
+ validates :email, uniqueness: { case_sensitive: false }, allow_nil: true
68
+ validates_length_of :slug, maximum: SLUG_LIMIT
69
+ validates_length_of :screen_name, maximum: SLUG_LIMIT
70
+ validates_length_of :email, maximum: EMAIL_LIMIT
71
+ validates_length_of :phone, maximum: PHONE_LIMIT
72
+ validates_length_of :notice, maximum: NOTICE_LIMIT
73
+
74
+ scope :bots, ->(f) { where(bot: f.to_i.positive?) unless f.blank? }
75
+ scope :email_like, ->(v) { where('email ilike ?', "%#{v}%") unless v.blank? }
76
+ scope :with_email, ->(v) { where('lower(email) = lower(?)', v) }
77
+
78
+ def self.profile_parameters
79
+ %i[image allow_mail birthday consent]
80
+ end
81
+
82
+ def self.sensitive_parameters
83
+ %i[email phone password password_confirmation]
84
+ end
85
+
86
+ # Параметры при регистрации
87
+ def self.new_profile_parameters
88
+ profile_parameters + sensitive_parameters + %i[screen_name]
89
+ end
90
+
91
+ # Administrative parameters
92
+ def self.entity_parameters
93
+ flags = %i[banned bot email_confirmed phone_confirmed foreign_slug]
94
+
95
+ new_profile_parameters + flags + %i[screen_name notice balance]
96
+ end
97
+
98
+ def self.ids_range
99
+ min = User.minimum(:id).to_i
100
+ max = User.maximum(:id).to_i
101
+ (min..max)
102
+ end
103
+
104
+ # Name to be shown as profile
105
+ #
106
+ # This can be redefined for cases when something other than screen name should
107
+ # be used.
108
+ #
109
+ # @return [String]
110
+ def profile_name
111
+ screen_name
112
+ end
113
+
114
+ def name_for_letter
115
+ data.dig('profile', 'name').blank? ? profile_name : data['profile']['name']
116
+ end
117
+
118
+ # @param [TrueClass|FalseClass] include_patronymic
119
+ def full_name(include_patronymic = false)
120
+ result = [name_for_letter]
121
+ result << data.dig('profile', 'patronymic').to_s.strip if include_patronymic
122
+ result << data.dig('profile', 'surname').to_s.strip
123
+ result.compact.join(' ')
124
+ end
125
+
126
+ def can_receive_letters?
127
+ allow_mail? && !email.blank?
128
+ end
129
+
130
+ private
131
+
132
+ def normalize_slug
133
+ self.slug = screen_name.to_s if slug.nil?
134
+ self.slug = slug.to_s.downcase
135
+ end
136
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Language for user
4
+ #
5
+ # Attributes:
6
+ # created_at [DateTime]
7
+ # language_id [Language]
8
+ # updated_at [DateTime]
9
+ # user_id [User]
10
+ class UserLanguage < ApplicationRecord
11
+ include HasOwner
12
+
13
+ belongs_to :user
14
+ belongs_to :language
15
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Uploader for universal simple images
4
+ class SimpleImageUploader < CarrierWave::Uploader::Base
5
+ include CarrierWave::MiniMagick
6
+
7
+ storage :file
8
+
9
+ def store_dir
10
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{path_slug}"
11
+ end
12
+
13
+ def default_url(*)
14
+ ActionController::Base.helpers.asset_path('biovision/placeholders/1x1.svg')
15
+ end
16
+
17
+ version :hd, if: :raster_image? do
18
+ resize_to_fit(1920, 1920)
19
+ end
20
+
21
+ version :large, from_version: :hd, if: :raster_image? do
22
+ resize_to_fit(1280, 1280)
23
+ end
24
+
25
+ version :medium, from_version: :large, if: :raster_image? do
26
+ resize_to_fit(640, 640)
27
+ end
28
+
29
+ version :small, from_version: :medium, if: :raster_image? do
30
+ resize_to_fit(320, 320)
31
+ end
32
+
33
+ version :preview, from_version: :small, if: :raster_image? do
34
+ resize_to_fit(160, 160)
35
+ end
36
+
37
+ # Add a white list of extensions which are allowed to be uploaded.
38
+ # For images you might use something like this:
39
+ def extension_whitelist
40
+ %w[jpg jpeg png svg svgz]
41
+ end
42
+
43
+ # Text for image alt attribute
44
+ #
45
+ # @param [String] default
46
+ # @return [String]
47
+ def alt_text(default = '')
48
+ method_name = "#{mounted_as}_alt_text".to_sym
49
+ if model.respond_to?(method_name)
50
+ model.send(method_name)
51
+ else
52
+ default
53
+ end
54
+ end
55
+
56
+ # @param [SanitizedFile]
57
+ def raster_image?(new_file)
58
+ !new_file.extension.match?(/svgz?\z/i)
59
+ end
60
+
61
+ def raster?
62
+ !File.extname(path).match?(/\.svgz?\z/i)
63
+ end
64
+
65
+ def preview_url
66
+ raster? ? preview.url : url
67
+ end
68
+
69
+ def small_url
70
+ raster? ? small.url : url
71
+ end
72
+
73
+ def medium_url
74
+ raster? ? medium.url : url
75
+ end
76
+
77
+ def large_url
78
+ raster? ? large.url : url
79
+ end
80
+
81
+ def hd_url
82
+ raster? ? hd.url : url
83
+ end
84
+
85
+ private
86
+
87
+ def path_slug
88
+ if model.respond_to?(:uuid)
89
+ uuid = model&.uuid.to_s
90
+ "#{uuid[0..2]}/#{uuid[3..5]}/#{uuid[6..7]}/#{uuid}"
91
+ else
92
+ id = model&.id.to_i
93
+ "#{id / 1000}/#{id}"
94
+ end
95
+ end
96
+ end