biovision 0.0.200518.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +214 -0
- data/Rakefile +22 -0
- data/app/assets/config/biovision_manifest.js +1 -0
- data/app/assets/images/biovision/components/carousel/arrow-left.svg +4 -0
- data/app/assets/images/biovision/components/carousel/arrow-right.svg +4 -0
- data/app/assets/images/biovision/icons/breadcrumb-hover.svg +1 -0
- data/app/assets/images/biovision/icons/breadcrumb.svg +1 -0
- data/app/assets/images/biovision/icons/components/contact.svg +26 -0
- data/app/assets/images/biovision/icons/components/content.svg +20 -0
- data/app/assets/images/biovision/icons/components/users.svg +21 -0
- data/app/assets/images/biovision/icons/key.svg +16 -0
- data/app/assets/images/biovision/icons/log_in.svg +15 -0
- data/app/assets/images/biovision/icons/log_out.svg +15 -0
- data/app/assets/images/biovision/icons/messages/error.svg +14 -0
- data/app/assets/images/biovision/icons/messages/info.svg +8 -0
- data/app/assets/images/biovision/icons/messages/success.svg +12 -0
- data/app/assets/images/biovision/icons/messages/warning.svg +13 -0
- data/app/assets/images/biovision/icons/settings.svg +41 -0
- data/app/assets/images/biovision/placeholders/16x9.svg +11 -0
- data/app/assets/images/biovision/placeholders/1x1.svg +11 -0
- data/app/assets/images/biovision/placeholders/3x2.svg +11 -0
- data/app/assets/images/biovision/placeholders/user.svg +15 -0
- data/app/assets/stylesheets/biovision/admin.scss +6 -0
- data/app/assets/stylesheets/biovision/admin/components.scss +59 -0
- data/app/assets/stylesheets/biovision/admin/default.scss +57 -0
- data/app/assets/stylesheets/biovision/admin/layout.scss +95 -0
- data/app/assets/stylesheets/biovision/admin/vars.scss +56 -0
- data/app/assets/stylesheets/biovision/biovision.scss +134 -0
- data/app/assets/stylesheets/biovision/biovision/messages.scss +41 -0
- data/app/assets/stylesheets/biovision/components/carousel.scss +53 -0
- data/app/assets/stylesheets/biovision/components/forms.scss +85 -0
- data/app/assets/stylesheets/biovision/components/hamburger.scss +56 -0
- data/app/assets/stylesheets/biovision/components/lists.scss +91 -0
- data/app/assets/stylesheets/biovision/default.scss +57 -0
- data/app/assets/stylesheets/biovision/themes/default_theme.scss +2 -0
- data/app/assets/stylesheets/biovision/themes/default_theme/components.scss +3 -0
- data/app/assets/stylesheets/biovision/themes/default_theme/layout.scss +44 -0
- data/app/assets/stylesheets/biovision/themes/default_theme/layout/footer.scss +0 -0
- data/app/assets/stylesheets/biovision/themes/default_theme/layout/header.scss +39 -0
- data/app/assets/stylesheets/biovision/vars.scss +53 -0
- data/app/controllers/admin/agents_controller.rb +15 -0
- data/app/controllers/admin/components_controller.rb +174 -0
- data/app/controllers/admin/index_controller.rb +11 -0
- data/app/controllers/admin/ip_addresses_controller.rb +15 -0
- data/app/controllers/admin_controller.rb +14 -0
- data/app/controllers/authentication_controller.rb +79 -0
- data/app/controllers/concerns/authentication.rb +45 -0
- data/app/controllers/index_controller.rb +8 -0
- data/app/controllers/my/confirmations_controller.rb +2 -0
- data/app/controllers/my/index_controller.rb +8 -0
- data/app/controllers/my/profiles_controller.rb +128 -0
- data/app/controllers/my/recoveries_controller.rb +2 -0
- data/app/helpers/biovision_components_helper.rb +14 -0
- data/app/helpers/users_helper.rb +11 -0
- data/app/lib/biovision/components/base_component.rb +177 -0
- data/app/lib/biovision/components/component_settings.rb +30 -0
- data/app/lib/biovision/components/privilege_handler.rb +77 -0
- data/app/lib/biovision/components/track_component.rb +9 -0
- data/app/lib/biovision/components/users/authentication.rb +47 -0
- data/app/lib/biovision/components/users/code_handler.rb +23 -0
- data/app/lib/biovision/components/users/profile_handler.rb +12 -0
- data/app/lib/biovision/components/users/registration_handler.rb +99 -0
- data/app/lib/biovision/components/users_component.rb +47 -0
- data/app/lib/biovision/notifiers/base_notifier.rb +69 -0
- data/app/lib/biovision/notifiers/socialization_notifier.rb +31 -0
- data/app/lib/biovision/notifiers/users_notifier.rb +15 -0
- data/app/models/agent.rb +35 -0
- data/app/models/biovision_component.rb +45 -0
- data/app/models/biovision_component_user.rb +21 -0
- data/app/models/browser.rb +34 -0
- data/app/models/code.rb +71 -0
- data/app/models/concerns/checkable.rb +22 -0
- data/app/models/concerns/flat_priority.rb +50 -0
- data/app/models/concerns/has_language.rb +10 -0
- data/app/models/concerns/has_owner.rb +22 -0
- data/app/models/concerns/has_simple_image.rb +18 -0
- data/app/models/concerns/has_track.rb +10 -0
- data/app/models/concerns/has_uuid.rb +12 -0
- data/app/models/concerns/meta_texts.rb +16 -0
- data/app/models/concerns/nested_priority.rb +58 -0
- data/app/models/concerns/required_unique_name.rb +16 -0
- data/app/models/concerns/required_unique_slug.rb +15 -0
- data/app/models/concerns/toggleable.rb +33 -0
- data/app/models/foreign_site.rb +34 -0
- data/app/models/foreign_user.rb +21 -0
- data/app/models/ip_address.rb +31 -0
- data/app/models/language.rb +31 -0
- data/app/models/login_attempt.rb +35 -0
- data/app/models/metric.rb +48 -0
- data/app/models/metric_value.rb +11 -0
- data/app/models/notification.rb +37 -0
- data/app/models/simple_image.rb +47 -0
- data/app/models/simple_image_tag.rb +30 -0
- data/app/models/simple_image_tag_image.rb +13 -0
- data/app/models/token.rb +96 -0
- data/app/models/user.rb +136 -0
- data/app/models/user_language.rb +15 -0
- data/app/uploaders/simple_image_uploader.rb +96 -0
- data/app/uploaders/user_image_uploader.rb +58 -0
- data/app/views/admin/agents/_nav_item.html.erb +6 -0
- data/app/views/admin/agents/entity/_in_list.html.erb +6 -0
- data/app/views/admin/agents/index.html.erb +13 -0
- data/app/views/admin/components/_list.html.erb +12 -0
- data/app/views/admin/components/entity/_links.html.erb +35 -0
- data/app/views/admin/components/entity/_section.html.erb +12 -0
- data/app/views/admin/components/index.html.erb +12 -0
- data/app/views/admin/components/links/_track.html.erb +2 -0
- data/app/views/admin/components/links/_users.html.erb +11 -0
- data/app/views/admin/components/privileges.html.erb +20 -0
- data/app/views/admin/components/privileges/_component_user.html.erb +17 -0
- data/app/views/admin/components/privileges/_links.html.erb +35 -0
- data/app/views/admin/components/privileges/_privilege_flag.html.erb +28 -0
- data/app/views/admin/components/privileges/_users.html.erb +23 -0
- data/app/views/admin/components/settings.html.erb +39 -0
- data/app/views/admin/components/settings/_new_parameter.html.erb +46 -0
- data/app/views/admin/components/settings/_parameters.html.erb +20 -0
- data/app/views/admin/components/settings/_setting.html.erb +18 -0
- data/app/views/admin/components/settings/_settings.html.erb +31 -0
- data/app/views/admin/components/show.html.erb +14 -0
- data/app/views/admin/index/index.html.erb +14 -0
- data/app/views/admin/ip_addresses/_nav_item.html.erb +6 -0
- data/app/views/admin/ip_addresses/entity/_in_list.html.erb +6 -0
- data/app/views/admin/ip_addresses/index.html.erb +13 -0
- data/app/views/admin/unauthorized.html.erb +19 -0
- data/app/views/authentication/_form.html.erb +40 -0
- data/app/views/authentication/failed.js.erb +3 -0
- data/app/views/authentication/new.html.erb +21 -0
- data/app/views/index/index.html.erb +0 -0
- data/app/views/layouts/admin.html.erb +23 -0
- data/app/views/layouts/admin/_breadcrumbs.html.erb +8 -0
- data/app/views/layouts/admin/_footer.html.erb +10 -0
- data/app/views/layouts/admin/_header.html.erb +18 -0
- data/app/views/layouts/admin/header/_logo.html.erb +3 -0
- data/app/views/layouts/application/_footer.html.erb +8 -0
- data/app/views/layouts/application/_header.html.erb +9 -0
- data/app/views/layouts/application/header/_authentication.html.erb +13 -0
- data/app/views/my/index/index.html.erb +0 -0
- data/app/views/my/profiles/closed.html.erb +12 -0
- data/app/views/my/profiles/new.html.erb +17 -0
- data/app/views/my/profiles/new/_form.html.erb +147 -0
- data/app/views/shared/_breadcrumbs.html.erb +8 -0
- data/app/views/shared/_cookie_notification.html.erb +4 -0
- data/app/views/shared/_flash_messages.html.erb +7 -0
- data/app/views/shared/_meta_texts.html.erb +31 -0
- data/app/views/shared/_nothing_found.html.erb +1 -0
- data/app/views/shared/_pagination.jbuilder +15 -0
- data/app/views/shared/admin/_list.html.erb +19 -0
- data/app/views/shared/admin/_list_with_priority.html.erb +19 -0
- data/app/views/shared/admin/_toggleable.html.erb +8 -0
- data/app/views/shared/entity/_list_of_errors.html.erb +7 -0
- data/app/views/shared/forms/errors.js.erb +5 -0
- data/config/initializers/carrierwave.rb +27 -0
- data/config/initializers/pluralization.rb +2 -0
- data/config/locales/biovision-ru.yml +90 -0
- data/config/locales/components-ru.yml +81 -0
- data/config/locales/track-ru.yml +40 -0
- data/config/locales/users-ru.yml +130 -0
- data/config/routes.rb +75 -0
- data/db/migrate/20191228000000_create_biovision_components.rb +72 -0
- data/db/migrate/20200224000000_create_track_component.rb +59 -0
- data/db/migrate/20200224000010_create_users_component.rb +189 -0
- data/db/migrate/20200404000000_create_simple_images.rb +54 -0
- data/lib/biovision.rb +9 -0
- data/lib/biovision/base_methods.rb +167 -0
- data/lib/biovision/engine.rb +40 -0
- data/lib/biovision/version.rb +5 -0
- data/lib/tasks/biovision_tasks.rake +4 -0
- metadata +392 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Adds ownership to model
|
4
|
+
module HasOwner
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
scope :owned_by, ->(v) { where(user: v) }
|
9
|
+
scope :with_user_id, ->(v) { where(user_id: v) unless v.blank? }
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param [User] user
|
13
|
+
# @return [Boolean]
|
14
|
+
def owned_by?(user)
|
15
|
+
!user.nil? && (self.user == user)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String]
|
19
|
+
def owner_name
|
20
|
+
user&.profile_name || I18n.t(:anonymous)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Model references to simple image
|
4
|
+
module HasSimpleImage
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
belongs_to :simple_image, optional: true, counter_cache: :object_count
|
9
|
+
end
|
10
|
+
|
11
|
+
def image
|
12
|
+
simple_image&.image
|
13
|
+
end
|
14
|
+
|
15
|
+
def image_alt_text
|
16
|
+
simple_image&.image_alt_text
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Adds UUID field and constraints to model
|
4
|
+
module HasUuid
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
after_initialize { self.uuid = SecureRandom.uuid if uuid.nil? }
|
9
|
+
validates_presence_of :uuid
|
10
|
+
validates_uniqueness_of :uuid
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Model has meta description, keywords and title
|
4
|
+
module MetaTexts
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
validates_length_of :meta_description, maximum: 500
|
9
|
+
validates_length_of :meta_keywords, maximum: 250
|
10
|
+
validates_length_of :meta_title, maximum: 250
|
11
|
+
|
12
|
+
def self.meta_text_fields
|
13
|
+
%i[meta_description meta_keywords meta_title]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Model has nested priority field
|
4
|
+
#
|
5
|
+
# Adds sorting items by priority with siblings
|
6
|
+
# @author Maxim Khan-Magomedov <maxim.km@gmail.com>
|
7
|
+
module NestedPriority
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
after_initialize :set_next_priority
|
12
|
+
before_validation :normalize_priority
|
13
|
+
|
14
|
+
scope :ordered_by_priority, -> { order('priority asc, id asc') }
|
15
|
+
|
16
|
+
def self.priority_range
|
17
|
+
(1..32_767)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Change this method in models to get siblings
|
21
|
+
#
|
22
|
+
# @param [ApplicationRecord] _entity
|
23
|
+
def self.siblings(_entity)
|
24
|
+
all
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [Integer] delta
|
29
|
+
def change_priority(delta)
|
30
|
+
swap_priority_with_adjacent(priority + delta)
|
31
|
+
|
32
|
+
siblings = self.class.siblings(self)
|
33
|
+
siblings.ordered_by_priority.map { |e| [e.id, e.priority] }.to_h
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
# @param [Integer] new_priority
|
39
|
+
def swap_priority_with_adjacent(new_priority)
|
40
|
+
adjacent = self.class.siblings(self).find_by(priority: new_priority)
|
41
|
+
if adjacent.is_a?(self.class) && (adjacent.id != id)
|
42
|
+
adjacent.update!(priority: priority)
|
43
|
+
end
|
44
|
+
update(priority: new_priority)
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_next_priority
|
48
|
+
return unless id.nil? && priority == 1
|
49
|
+
|
50
|
+
self.priority = self.class.siblings(self).maximum(:priority).to_i + 1
|
51
|
+
end
|
52
|
+
|
53
|
+
def normalize_priority
|
54
|
+
range = self.class.priority_range
|
55
|
+
self.priority = range.first if priority < range.first
|
56
|
+
self.priority = range.last if priority > range.last
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Mixin for adding required unique name constrain
|
4
|
+
module RequiredUniqueName
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_validation { self.name = name.strip unless name.nil? }
|
9
|
+
validates_presence_of :name
|
10
|
+
validates_uniqueness_of :name
|
11
|
+
|
12
|
+
scope :ordered_by_name, -> { order('name asc') }
|
13
|
+
scope :with_name_like, ->(v) { where('name ilike ?', "%#{v}%") unless v.blank? }
|
14
|
+
scope :with_name, ->(v) { where('lower(name) = lower(?)', v) unless v.blank? }
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Mixin for adding required unique slug constrain
|
4
|
+
module RequiredUniqueSlug
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_validation { self.slug = slug.strip unless slug.nil? }
|
9
|
+
validates :slug, uniqueness: { case_sensitive: false }, presence: true
|
10
|
+
|
11
|
+
scope :ordered_by_slug, -> { order('slug asc') }
|
12
|
+
scope :with_slug_like, ->(v) { where('slug ilike ?', "%#{v}%") unless v.blank? }
|
13
|
+
scope :with_slug, ->(v) { where('lower(slug) = lower(?)', v) unless v.blank? }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Adds list of toggleable attributes to model
|
4
|
+
#
|
5
|
+
# @author Maxim Khan-Magomedov <maxim.km@gmail.com>
|
6
|
+
module Toggleable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
class_attribute :toggleable_attributes, instance_predicate: false, instance_accessor: false
|
11
|
+
|
12
|
+
# @param [String, Symbol] attribute
|
13
|
+
# @return [Hash]
|
14
|
+
def toggle_parameter(attribute)
|
15
|
+
return unless toggleable_attributes.include? attribute.to_sym
|
16
|
+
|
17
|
+
toggle! attribute
|
18
|
+
{ attribute => self[attribute] }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Additional class methods
|
23
|
+
module ClassMethods
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# @param [Array<Symbol>] attributes
|
28
|
+
def toggleable(*attributes)
|
29
|
+
cattr_accessor :toggleable_attributes
|
30
|
+
self.toggleable_attributes = attributes.flatten
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Foreign site for external authentication
|
4
|
+
#
|
5
|
+
# Attributes:
|
6
|
+
# slug [string]
|
7
|
+
# name [string]
|
8
|
+
# foreign_users_count [integer]
|
9
|
+
class ForeignSite < ApplicationRecord
|
10
|
+
include RequiredUniqueName
|
11
|
+
include RequiredUniqueSlug
|
12
|
+
|
13
|
+
NAME_LIMIT = 50
|
14
|
+
SLUG_LIMIT = 50
|
15
|
+
|
16
|
+
has_many :foreign_users, dependent: :delete_all
|
17
|
+
|
18
|
+
validates_length_of :name, maximum: NAME_LIMIT
|
19
|
+
validates_length_of :slug, maximum: SLUG_LIMIT
|
20
|
+
|
21
|
+
scope :list_for_administration, -> { ordered_by_name }
|
22
|
+
|
23
|
+
# @param [String] slug
|
24
|
+
def self.[](slug)
|
25
|
+
find_by(slug: slug)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [Hash] data
|
29
|
+
# @param [Hash] tracking
|
30
|
+
def authenticate(data, tracking)
|
31
|
+
user = foreign_users.find_by(slug: data[:uid])&.user
|
32
|
+
user || create_user(data, tracking)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Foreign user
|
4
|
+
#
|
5
|
+
# Attributes:
|
6
|
+
# agent_id [Agent], optional
|
7
|
+
# created_at [DateTime]
|
8
|
+
# data [jsonb]
|
9
|
+
# foreign_site_id [ForeignSite]
|
10
|
+
# ip_address_id [IpAddress], optional
|
11
|
+
# updated_at [DateTime]
|
12
|
+
# user_id [User]
|
13
|
+
# slug [string]
|
14
|
+
class ForeignUser < ApplicationRecord
|
15
|
+
include HasOwner
|
16
|
+
|
17
|
+
belongs_to :foreign_site
|
18
|
+
belongs_to :user
|
19
|
+
belongs_to :agent
|
20
|
+
belongs_to :ip_address
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# IP address
|
4
|
+
#
|
5
|
+
# Attributes:
|
6
|
+
# banned [boolean]
|
7
|
+
# created_at [DateTime]
|
8
|
+
# ip [inet]
|
9
|
+
# object_count [integer]
|
10
|
+
# updated_at [DateTime]
|
11
|
+
class IpAddress < ApplicationRecord
|
12
|
+
include Toggleable
|
13
|
+
|
14
|
+
toggleable :banned
|
15
|
+
|
16
|
+
validates_uniqueness_of :ip
|
17
|
+
|
18
|
+
scope :list_for_administration, -> { order('ip asc') }
|
19
|
+
|
20
|
+
# @param [Integer] page
|
21
|
+
def self.page_for_administration(page = 1)
|
22
|
+
list_for_administration.page(page)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param [String] ip
|
26
|
+
def self.[](ip)
|
27
|
+
return if ip.blank?
|
28
|
+
|
29
|
+
find_or_create_by(ip: ip)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Language
|
4
|
+
#
|
5
|
+
# Attributes:
|
6
|
+
# active [Boolean]
|
7
|
+
# code [String]
|
8
|
+
# created_at [DateTime]
|
9
|
+
# object_count [Integer]
|
10
|
+
# priority [Integer]
|
11
|
+
# slug [String]
|
12
|
+
# updated_at [DateTime]
|
13
|
+
class Language < ApplicationRecord
|
14
|
+
include FlatPriority
|
15
|
+
include RequiredUniqueSlug
|
16
|
+
|
17
|
+
CODE_PATTERN = /\A[a-z]{2,3}(-[A-z][a-z]{3})?(-[A-Z]{2})?\z/.freeze
|
18
|
+
SLUG_PATTERN = /\A[a-z][-a-z0-9]{,18}[a-z0-9]\z/.freeze
|
19
|
+
|
20
|
+
validates_presence_of :code
|
21
|
+
validates_uniqueness_of :code
|
22
|
+
validates_format_of :code, with: CODE_PATTERN
|
23
|
+
validates_format_of :slug, with: SLUG_PATTERN
|
24
|
+
|
25
|
+
scope :active, -> { where(active: true) }
|
26
|
+
|
27
|
+
# @param [String|Symbol] code
|
28
|
+
def self.[](code)
|
29
|
+
find_by(code: code)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Failed login attempt
|
4
|
+
#
|
5
|
+
# Attributes:
|
6
|
+
# agent_id [Agent], optional
|
7
|
+
# created_at [DateTime]
|
8
|
+
# ip_address_id [IpAddress], optional
|
9
|
+
# updated_at [DateTime]
|
10
|
+
# user_id [User]
|
11
|
+
# password [string]
|
12
|
+
class LoginAttempt < ApplicationRecord
|
13
|
+
include HasOwner
|
14
|
+
include HasTrack
|
15
|
+
|
16
|
+
belongs_to :user
|
17
|
+
|
18
|
+
before_validation { self.password = password.to_s[0..254] }
|
19
|
+
|
20
|
+
scope :recent, -> { order('id desc') }
|
21
|
+
scope :since, ->(time) { where('created_at > ?', time) }
|
22
|
+
scope :list_for_administration, -> { recent }
|
23
|
+
scope :list_for_owner, ->(u) { owned_by(u).recent }
|
24
|
+
|
25
|
+
# @param [Integer] page
|
26
|
+
def self.page_for_administration(page = 1)
|
27
|
+
list_for_administration.page(page)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param [User] user
|
31
|
+
# @param [Integer] page
|
32
|
+
def self.page_for_owner(user, page = 1)
|
33
|
+
list_for_owner(user).page(page)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Metric for component
|
4
|
+
#
|
5
|
+
# Attributes:
|
6
|
+
# biovision_component_id [BiovisionComponent]
|
7
|
+
# created_at [DateTime]
|
8
|
+
# default_period [integer]
|
9
|
+
# incremental [boolean]
|
10
|
+
# previous_value [integer]
|
11
|
+
# show_on_dashboard [boolean]
|
12
|
+
# start_with_zero [boolean]
|
13
|
+
# name [string]
|
14
|
+
# updated_at [DateTime]
|
15
|
+
# value [integer]
|
16
|
+
class Metric < ApplicationRecord
|
17
|
+
include RequiredUniqueName
|
18
|
+
include Toggleable
|
19
|
+
|
20
|
+
NAME_LIMIT = 255
|
21
|
+
PERIOD_RANGE = (1..366).freeze
|
22
|
+
|
23
|
+
belongs_to :biovision_component
|
24
|
+
has_many :metric_values, dependent: :delete_all
|
25
|
+
|
26
|
+
validates_length_of :name, maximum: NAME_LIMIT
|
27
|
+
|
28
|
+
|
29
|
+
def quantity
|
30
|
+
metric_values.sum(:quantity)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [Integer] input
|
34
|
+
def <<(input)
|
35
|
+
metric_values.create(time: Time.now, quantity: input)
|
36
|
+
|
37
|
+
update(value: incremental? ? quantity : input, previous_value: value)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [Integer] period
|
41
|
+
def values(period = 7)
|
42
|
+
current_value = 0
|
43
|
+
metric_values.since(period.days.ago).ordered_by_time.map do |v|
|
44
|
+
current_value = incremental? ? current_value + v.quantity : v.quantity
|
45
|
+
[v.time.strftime('%d.%m.%Y %H:%M'), current_value]
|
46
|
+
end.to_h
|
47
|
+
end
|
48
|
+
end
|