student_mvp 0.1.0

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 (127) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +35 -0
  3. data/Rakefile +4 -0
  4. data/doc/Add_student_presenter.html +238 -0
  5. data/doc/App_logger.html +386 -0
  6. data/doc/Base_presenter.html +265 -0
  7. data/doc/Binary_tree.html +300 -0
  8. data/doc/Binary_tree_iterator.html +217 -0
  9. data/doc/Contact_sort_decorator.html +219 -0
  10. data/doc/DB_client.html +252 -0
  11. data/doc/Data_list.html +625 -0
  12. data/doc/Data_list_student_short.html +148 -0
  13. data/doc/Data_storage_strategy.html +178 -0
  14. data/doc/Data_table.html +264 -0
  15. data/doc/Deep_dup.html +152 -0
  16. data/doc/Edit_contacts_presenter.html +199 -0
  17. data/doc/Edit_git_presenter.html +192 -0
  18. data/doc/Edit_student_presenter.html +464 -0
  19. data/doc/Field_filter_decorator.html +219 -0
  20. data/doc/Filter.html +148 -0
  21. data/doc/Filter_decorator.html +209 -0
  22. data/doc/Full_name_filter_decorator.html +211 -0
  23. data/doc/Full_name_sort_decorator.html +217 -0
  24. data/doc/Gemfile.html +98 -0
  25. data/doc/Git_sort_decorator.html +220 -0
  26. data/doc/Has_not_field_filter_decorator.html +209 -0
  27. data/doc/JSON_storage_strategy.html +183 -0
  28. data/doc/Person.html +511 -0
  29. data/doc/README_md.html +147 -0
  30. data/doc/Rakefile.html +94 -0
  31. data/doc/Replace_student_presenter.html +204 -0
  32. data/doc/Sort_decorator.html +214 -0
  33. data/doc/Student.html +755 -0
  34. data/doc/StudentMvp/Error.html +105 -0
  35. data/doc/StudentMvp.html +111 -0
  36. data/doc/Student_list_presenter.html +667 -0
  37. data/doc/Student_short.html +398 -0
  38. data/doc/Students_list.html +341 -0
  39. data/doc/Students_list_DB.html +361 -0
  40. data/doc/Students_list_file.html +460 -0
  41. data/doc/Students_list_file_adapter.html +341 -0
  42. data/doc/Students_list_interface.html +298 -0
  43. data/doc/YAML_storage_strategy.html +183 -0
  44. data/doc/bin/setup.html +96 -0
  45. data/doc/created.rid +44 -0
  46. data/doc/css/fonts.css +167 -0
  47. data/doc/css/rdoc.css +662 -0
  48. data/doc/fonts/Lato-Light.ttf +0 -0
  49. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  50. data/doc/fonts/Lato-Regular.ttf +0 -0
  51. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  52. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  53. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  54. data/doc/images/add.png +0 -0
  55. data/doc/images/arrow_up.png +0 -0
  56. data/doc/images/brick.png +0 -0
  57. data/doc/images/brick_link.png +0 -0
  58. data/doc/images/bug.png +0 -0
  59. data/doc/images/bullet_black.png +0 -0
  60. data/doc/images/bullet_toggle_minus.png +0 -0
  61. data/doc/images/bullet_toggle_plus.png +0 -0
  62. data/doc/images/date.png +0 -0
  63. data/doc/images/delete.png +0 -0
  64. data/doc/images/find.png +0 -0
  65. data/doc/images/loadingAnimation.gif +0 -0
  66. data/doc/images/macFFBgHack.png +0 -0
  67. data/doc/images/package.png +0 -0
  68. data/doc/images/page_green.png +0 -0
  69. data/doc/images/page_white_text.png +0 -0
  70. data/doc/images/page_white_width.png +0 -0
  71. data/doc/images/plugin.png +0 -0
  72. data/doc/images/ruby.png +0 -0
  73. data/doc/images/tag_blue.png +0 -0
  74. data/doc/images/tag_green.png +0 -0
  75. data/doc/images/transparent.png +0 -0
  76. data/doc/images/wrench.png +0 -0
  77. data/doc/images/wrench_orange.png +0 -0
  78. data/doc/images/zoom.png +0 -0
  79. data/doc/index.html +174 -0
  80. data/doc/js/darkfish.js +114 -0
  81. data/doc/js/navigation.js +105 -0
  82. data/doc/js/navigation.js.gz +0 -0
  83. data/doc/js/search.js +110 -0
  84. data/doc/js/search_index.js +1 -0
  85. data/doc/js/search_index.js.gz +0 -0
  86. data/doc/js/searcher.js +229 -0
  87. data/doc/js/searcher.js.gz +0 -0
  88. data/doc/table_of_contents.html +1047 -0
  89. data/lib/data_access/DB_client/DB_client.rb +26 -0
  90. data/lib/deep_dup/deep_dup.rb +14 -0
  91. data/lib/logger/logger.rb +64 -0
  92. data/lib/models/binary_tree/binary_tree.rb +163 -0
  93. data/lib/models/binary_tree/binary_tree_iterator.rb +36 -0
  94. data/lib/models/data_list/data_list.rb +97 -0
  95. data/lib/models/data_list/data_list_student_short.rb +16 -0
  96. data/lib/models/data_storage_strategy/JSON_storage_strategy.rb +20 -0
  97. data/lib/models/data_storage_strategy/YAML_storage_strategy.rb +20 -0
  98. data/lib/models/data_storage_strategy/data_storage_strategy.rb +11 -0
  99. data/lib/models/data_table/data_table.rb +52 -0
  100. data/lib/models/filter/filter.rb +5 -0
  101. data/lib/models/filter/filter_decorator.rb +14 -0
  102. data/lib/models/filter/sort_decorator.rb +15 -0
  103. data/lib/models/filter/student_filters/contact_sort_decorator.rb +50 -0
  104. data/lib/models/filter/student_filters/field_filter_decorator.rb +34 -0
  105. data/lib/models/filter/student_filters/full_name_filter_decorator.rb +26 -0
  106. data/lib/models/filter/student_filters/full_name_sort_decorator.rb +32 -0
  107. data/lib/models/filter/student_filters/git_sort_decorator.rb +35 -0
  108. data/lib/models/filter/student_filters/has_not_field_filter_decorator.rb +24 -0
  109. data/lib/models/person/person.rb +72 -0
  110. data/lib/models/student/student.rb +204 -0
  111. data/lib/models/student_short/student_short.rb +98 -0
  112. data/lib/models/students_list/students_list.rb +32 -0
  113. data/lib/models/students_list/students_list_DB.rb +95 -0
  114. data/lib/models/students_list/students_list_file.rb +134 -0
  115. data/lib/models/students_list/students_list_file_adapter.rb +45 -0
  116. data/lib/models/students_list/students_list_interface.rb +25 -0
  117. data/lib/presenters/base_presenters/base_presenter.rb +26 -0
  118. data/lib/presenters/base_presenters/student_list_presenter.rb +273 -0
  119. data/lib/presenters/edit_student/add_student_presenter.rb +46 -0
  120. data/lib/presenters/edit_student/edit_contacts_presenter.rb +36 -0
  121. data/lib/presenters/edit_student/edit_git_presenter.rb +28 -0
  122. data/lib/presenters/edit_student/edit_student_presenter.rb +109 -0
  123. data/lib/presenters/edit_student/replace_student_presenter.rb +37 -0
  124. data/lib/student_mvp/version.rb +5 -0
  125. data/lib/student_mvp.rb +8 -0
  126. data/sig/student_mvp.rbs +4 -0
  127. metadata +253 -0
@@ -0,0 +1,26 @@
1
+ require 'mysql2'
2
+
3
+ class DB_client
4
+ private_class_method :new
5
+
6
+ def initialize(db_config)
7
+ raise 'Database configuration is required' unless db_config
8
+ self.client = Mysql2::Client.new(db_config)
9
+ end
10
+
11
+ def self.instance(db_config = nil)
12
+ @instance ||= new(db_config)
13
+ end
14
+
15
+ def query(query, params=[])
16
+ self.client.prepare(query).execute(*params)
17
+ end
18
+
19
+ def close
20
+ self.client.close
21
+ end
22
+
23
+ private
24
+ attr_accessor :client
25
+ @instance = nil
26
+ end
@@ -0,0 +1,14 @@
1
+ module Deep_dup
2
+ # deep copy
3
+ def deep_dup(element)
4
+ if element.is_a?(Array)
5
+ element.map { |sub_element| deep_dup(sub_element) }
6
+ else
7
+ begin
8
+ element.dup
9
+ rescue
10
+ element
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,64 @@
1
+ require 'logger'
2
+
3
+ class App_logger
4
+ LOG_FILE_PATH = File.expand_path('../../log/app.log', __FILE__)
5
+ private_class_method :new
6
+
7
+ def initialize
8
+ ensure_log_directory
9
+ self.logger = Logger.new(LOG_FILE_PATH)
10
+ self.logger.formatter = proc do |severity, datetime, progname, msg|
11
+ "[#{datetime}] #{severity}: #{msg}\n"
12
+ end
13
+ setup_log_level
14
+ end
15
+
16
+ def self.instance
17
+ @instance ||= new
18
+ end
19
+
20
+ def log(severity, message)
21
+ self.logger.send(severity, message)
22
+ end
23
+
24
+ def info(message)
25
+ log(:info, message)
26
+ end
27
+
28
+ def debug(message)
29
+ log(:debug, message)
30
+ end
31
+
32
+ def error(message)
33
+ log(:error, message)
34
+ end
35
+
36
+ def warn(message)
37
+ log(:warn, message)
38
+ end
39
+
40
+ def fatal(message)
41
+ log(:fatal, message)
42
+ end
43
+
44
+ private
45
+ attr_accessor :logger
46
+
47
+ def ensure_log_directory
48
+ log_directory = File.dirname(LOG_FILE_PATH)
49
+ Dir.mkdir(log_directory) unless Dir.exist?(log_directory)
50
+ end
51
+
52
+ def setup_log_level
53
+ log_mode = ENV['LOG_MODE'] || 'hybrid'
54
+
55
+ case log_mode.downcase
56
+ when 'all'
57
+ self.logger.level = Logger::DEBUG
58
+ when 'errors'
59
+ self.logger.level = Logger::ERROR
60
+ when 'hybrid'
61
+ self.logger.level = Logger::INFO
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,163 @@
1
+ require_relative './binary_tree_iterator.rb'
2
+
3
+ class Binary_tree
4
+ include Enumerable
5
+
6
+ RED = true
7
+ BLACK = false
8
+
9
+ class Node
10
+ attr_accessor :value, :left, :right, :color, :parent
11
+
12
+ def initialize(value, color = RED)
13
+ self.value = value
14
+ self.left = nil
15
+ self.right = nil
16
+ self.color = color
17
+ self.parent = nil
18
+ end
19
+ end
20
+
21
+ attr_accessor :root
22
+
23
+ def initialize
24
+ self.root = nil
25
+ end
26
+
27
+ def add(value)
28
+ new_node = Node.new(value)
29
+ self.root = insert(self.root, new_node)
30
+ self.balance(new_node)
31
+ end
32
+
33
+ def each(&block)
34
+ iterator = Binary_tree_iterator.new(self.root)
35
+ iterator.each(&block)
36
+ end
37
+
38
+ def find(key)
39
+ result = nil
40
+ self.each do |value|
41
+ if value.key == key
42
+ result = value
43
+ break
44
+ end
45
+ end
46
+ result
47
+ end
48
+
49
+ private
50
+ def insert(root, node)
51
+ if root.nil?
52
+ return node
53
+ elsif node.value < root.value
54
+ root.left = insert(root.left, node)
55
+ root.left.parent = root
56
+ else
57
+ root.right = insert(root.right, node)
58
+ root.right.parent = root
59
+ end
60
+ root
61
+ end
62
+
63
+ # метод для балансировки узла
64
+ def balance(node)
65
+ while node != self.root && node.parent.color == RED
66
+ if node.parent == node.parent.parent.left
67
+ balance_with_uncle_on_left(node)
68
+ else
69
+ balance_with_uncle_on_right(node)
70
+ end
71
+ end
72
+ self.root.color = BLACK
73
+ end
74
+
75
+ # балансировка, когда дядя находится слева
76
+ def balance_with_uncle_on_left(node)
77
+ uncle = node.parent.parent.right
78
+
79
+ if uncle&.color == RED # дядя красный
80
+ recolor(node)
81
+ node = node.parent.parent # дед
82
+ else
83
+ if node == node.parent.right # правый узел
84
+ node = node.parent # поворот влево
85
+ left_rotate(node)
86
+ end
87
+ rotate_and_recolor(node) # поворот вправо и перекраска
88
+ end
89
+ end
90
+
91
+ # балансировка, когда дядя находится справа
92
+ def balance_with_uncle_on_right(node)
93
+ uncle = node.parent.parent.left
94
+
95
+ if uncle&.color == RED # дядя красный
96
+ recolor(node)
97
+ node = node.parent.parent # дед
98
+ else
99
+ if node == node.parent.left # левый узел
100
+ node = node.parent # поворот вправо
101
+ right_rotate(node)
102
+ end
103
+ rotate_and_recolor(node) # поворот вправо и перекраска
104
+ end
105
+ end
106
+
107
+ # перекраска дяди и деда
108
+ def recolor(node)
109
+ node.parent.color = BLACK # родителя в черный
110
+ node.parent.parent.color = RED # деда в красный
111
+ uncle = node.parent.parent.right
112
+ uncle.color = BLACK if uncle # дядю в черный
113
+ end
114
+
115
+ # поворачиваем узел вправо и перекрашиваем
116
+ def rotate_and_recolor(node)
117
+ node.parent.color = BLACK # родителя в черный
118
+ node.parent.parent.color = RED # деда в красный
119
+ right_rotate(node.parent.parent) # поворот деда вправо
120
+ end
121
+
122
+ # левое вращение
123
+ def left_rotate(node)
124
+ right_child = node.right
125
+ return if right_child.nil?
126
+
127
+ node.right = right_child.left
128
+ right_child.left.parent = node if right_child.left
129
+ right_child.parent = node.parent
130
+
131
+ if node.parent.nil?
132
+ self.root = right_child
133
+ elsif node == node.parent.left
134
+ node.parent.left = right_child
135
+ else
136
+ node.parent.right = right_child
137
+ end
138
+
139
+ right_child.left = node
140
+ node.parent = right_child
141
+ end
142
+
143
+ # правое вращение
144
+ def right_rotate(node)
145
+ left_child = node.left
146
+ return if left_child.nil?
147
+
148
+ node.left = left_child.right
149
+ left_child.right.parent = node if left_child.right
150
+ left_child.parent = node.parent
151
+
152
+ if node.parent.nil?
153
+ self.root = left_child
154
+ elsif node == node.parent.left
155
+ node.parent.left = left_child
156
+ else
157
+ node.parent.right = left_child
158
+ end
159
+
160
+ left_child.right = node
161
+ node.parent = left_child
162
+ end
163
+ end
@@ -0,0 +1,36 @@
1
+ class Binary_tree_iterator
2
+ include Enumerable
3
+
4
+ attr_reader :root
5
+
6
+ def initialize(root)
7
+ self.root = root
8
+ end
9
+
10
+ def each(&block)
11
+ self.enumerator.each(&block)
12
+ end
13
+
14
+ private
15
+ attr_writer :root
16
+
17
+ def enumerator
18
+ Enumerator.new do |yielder|
19
+ stack = []
20
+ push_left_branch(yielder, self.root, stack)
21
+ end
22
+ end
23
+
24
+ def push_left_branch(yielder, node, stack)
25
+ while node
26
+ yielder << node.value
27
+ stack.push(node)
28
+ node = node.left
29
+ end
30
+
31
+ until stack.empty?
32
+ current = stack.pop
33
+ push_left_branch(yielder, current.right, stack)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,97 @@
1
+ require_relative '../../deep_dup/deep_dup.rb'
2
+
3
+ class Data_list
4
+ include Deep_dup
5
+
6
+ attr_accessor :index, :count
7
+
8
+ # constructor
9
+ def initialize(elements)
10
+ self.data = elements
11
+ self.selected = []
12
+ self.index = 1
13
+ self.observers = []
14
+ end
15
+
16
+ # select element id by number
17
+ def select(number)
18
+ raise IndexError, "Index out of bounds" unless self.valid_index?(number)
19
+ self.selected << number unless self.selected.include?(number)
20
+ end
21
+
22
+ # get selected ids
23
+ def get_selected
24
+ ids = []
25
+ self.selected.each do |key|
26
+ ids << self.data[key].id
27
+ end
28
+ ids
29
+ end
30
+
31
+ # deselect
32
+ def deselect(number)
33
+ self.selected.delete(number) if self.selected.include?(number)
34
+ end
35
+
36
+ # clear selected
37
+ def clear_selected
38
+ self.selected = []
39
+ end
40
+
41
+ # pattern-method
42
+ def retrieve_data()
43
+ result = []
44
+ result << self.get_names
45
+ result.concat(self.get_data)
46
+ Data_table.new(result)
47
+ end
48
+
49
+ # get names (abstract)
50
+ def get_names
51
+ raise NotImplementedError, "Not implemented"
52
+ end
53
+
54
+ # get_data
55
+ def get_data()
56
+ result = []
57
+ self.data.each do |key, value|
58
+ row = build_row(key, value)
59
+ result.append(row)
60
+ end
61
+ result
62
+ end
63
+
64
+ # data setter
65
+ def data=(data)
66
+ @data = {}
67
+ data.each do |element|
68
+ @data[index] = deep_dup(element)
69
+ self.index += 1
70
+ end
71
+ end
72
+
73
+ def notify
74
+ observers.each do |observer|
75
+ observer.set_table_params(self.get_names, self.count)
76
+ observer.set_table_data(self.retrieve_data)
77
+ end
78
+ end
79
+
80
+ def add_observer(observer)
81
+ self.observers << observer
82
+ end
83
+
84
+ protected
85
+ attr_reader :data
86
+ attr_accessor :selected, :observers
87
+
88
+ # validate index
89
+ def valid_index?(index)
90
+ self.data.key?(index)
91
+ end
92
+
93
+ # build row method (abstract)
94
+ def build_row(index, obj)
95
+ raise NotImplementedError, "Not implemented"
96
+ end
97
+ end
@@ -0,0 +1,16 @@
1
+ require_relative '../data_list/data_list.rb'
2
+ require_relative '../data_table/data_table.rb'
3
+
4
+ class Data_list_student_short < Data_list
5
+ # get_names for student short
6
+ def get_names
7
+ ["№", "full name", "git", "contact"]
8
+ end
9
+
10
+ private
11
+
12
+ # build row for student short
13
+ def build_row(index, obj)
14
+ [index, obj.full_name, obj.git, obj.get_any_contact]
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'json'
2
+ require_relative '../student/student.rb'
3
+ require_relative './data_storage_strategy.rb'
4
+
5
+ class JSON_storage_strategy < Data_storage_strategy
6
+ # read from json file
7
+ def read(file_path)
8
+ return [] unless File.exist?(file_path)
9
+ data = JSON.parse(File.read(file_path), symbolize_names: true) rescue []
10
+ data.map do |data|
11
+ Student.new(**data)
12
+ end
13
+ end
14
+
15
+ # read to json file
16
+ def write(file_path, students)
17
+ data = students.map { |student| student.to_h }
18
+ File.write(file_path, JSON.pretty_generate(data))
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'yaml'
2
+ require_relative '../student/student.rb'
3
+ require_relative './data_storage_strategy.rb'
4
+
5
+ class YAML_storage_strategy < Data_storage_strategy
6
+ # read from yaml file
7
+ def read(file_path)
8
+ return [] unless File.exist?(file_path)
9
+ data = YAML.safe_load(File.read(file_path), permitted_classes: [Date, Symbol]) || []
10
+ data.map do |student|
11
+ Student.new_from_hash(student)
12
+ end
13
+ end
14
+
15
+ # read to yaml file
16
+ def write(file_path, students)
17
+ data = students.map { |student| student.to_h }
18
+ File.write(file_path, data.to_yaml)
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ class Data_storage_strategy
2
+ # read from file
3
+ def read(file_path)
4
+ raise NotImplementedError, 'Not implemented'
5
+ end
6
+
7
+ # write to file
8
+ def write(file_path, students)
9
+ raise NotImplementedError, 'Not implemented'
10
+ end
11
+ end
@@ -0,0 +1,52 @@
1
+ require_relative '../../deep_dup/deep_dup.rb'
2
+
3
+ class Data_table
4
+ include Deep_dup
5
+
6
+ # constructor
7
+ def initialize(data)
8
+ self.data = data
9
+ end
10
+
11
+ # row count
12
+ def row_count
13
+ self.data.size
14
+ end
15
+
16
+ # column count
17
+ def col_count
18
+ if self.data.empty?
19
+ return 0
20
+ end
21
+ self.data[0].size
22
+ end
23
+
24
+ # get element
25
+ def get(row, col)
26
+ raise IndexError, "Row out of bounds" unless self.valid_row?(row)
27
+ raise IndexError, "Column out of bounds" unless self.valid_col?(col)
28
+ self.deep_dup(self.data[row][col])
29
+ end
30
+
31
+ private
32
+ attr_reader :data
33
+
34
+ # data setter
35
+ def data=(data)
36
+ unless data.is_a?(Array) && data.all? {|row| row.is_a?(Array)}
37
+ raise ArgumentError, "Data must be a two-dimensional array"
38
+ end
39
+
40
+ @data = data.map{ |row| row.map { |element| deep_dup(element) }}
41
+ end
42
+
43
+ # row validation
44
+ def valid_row?(row)
45
+ row.between?(0, self.row_count - 1)
46
+ end
47
+
48
+ # column validation
49
+ def valid_col?(col)
50
+ col.between?(0, self.col_count - 1)
51
+ end
52
+ end
@@ -0,0 +1,5 @@
1
+ class Filter
2
+ def apply(filtering_obj)
3
+ filtering_obj
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ require_relative './filter.rb'
2
+
3
+ class Filter_decorator < Filter
4
+ def initialize(filter)
5
+ self.filter = filter
6
+ end
7
+
8
+ def apply(filtering_obj)
9
+ self.filter.apply(filtering_obj)
10
+ end
11
+
12
+ protected
13
+ attr_accessor :filter
14
+ end
@@ -0,0 +1,15 @@
1
+ require_relative './filter_decorator.rb'
2
+
3
+ class Sort_decorator < Filter_decorator
4
+ def initialize(filter, order)
5
+ super(filter)
6
+ self.order = order
7
+ end
8
+
9
+ def apply(filtering_obj)
10
+ raise NotImplementedError
11
+ end
12
+
13
+ protected
14
+ attr_accessor :order
15
+ end
@@ -0,0 +1,50 @@
1
+ require_relative '../filter_decorator.rb'
2
+
3
+ class Contact_sort_decorator < Filter_decorator
4
+ def initialize(filter, order)
5
+ super(filter)
6
+ self.order = order
7
+ end
8
+
9
+ def apply(filtering_obj)
10
+ if filtering_obj.is_a?(Array)
11
+ filtered_students = super(filtering_obj)
12
+ return [] if filtered_students.nil?
13
+
14
+ sorted_students = filtered_students.sort_by do |student|
15
+ self.get_priority(student)
16
+ end
17
+ sorted_students.reverse! if self.order == :desc
18
+ sorted_students
19
+ else
20
+ query = super(filtering_obj)
21
+ "#{query} ORDER BY
22
+ CASE
23
+ WHEN telegram IS NOT NULL AND telegram != '' THEN 1
24
+ WHEN email IS NOT NULL AND email != '' THEN 2
25
+ WHEN phone_number IS NOT NULL AND phone_number != '' THEN 3
26
+ ELSE 4
27
+ END #{self.order_clause}
28
+ "
29
+ end
30
+ end
31
+
32
+ private
33
+ attr_accessor :order
34
+
35
+ def order_clause
36
+ self.order == :asc ? 'ASC' : 'DESC'
37
+ end
38
+
39
+ def get_priority(student)
40
+ if student.telegram && !student.telegram.empty?
41
+ 1
42
+ elsif student.email && !student.email.empty?
43
+ 2
44
+ elsif student.phone_number && !student.phone_number.empty?
45
+ 3
46
+ else
47
+ 4
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../filter_decorator.rb'
2
+
3
+ class Field_filter_decorator < Filter_decorator
4
+ def initialize(filter, field, value)
5
+ super(filter)
6
+ self.field = field
7
+ self.value = value.strip.downcase
8
+ end
9
+
10
+ def apply(filtering_obj)
11
+ if filtering_obj.is_a?(Array)
12
+ super(filtering_obj).select do |student|
13
+ student_value = student.send(self.field).to_s.downcase
14
+ if self.value.nil? || self.value.empty?
15
+ !student_value.nil? && !student_value.empty?
16
+ else
17
+ student_value.include?(self.value)
18
+ end
19
+ end
20
+ else
21
+ query = super(filtering_obj)
22
+ condition = query.include?("WHERE") ? "AND" : "WHERE"
23
+ if self.value.nil? || self.value.empty?
24
+ "#{query} #{condition} (#{self.field} IS NOT NULL AND #{self.field} != '')"
25
+ else
26
+ "#{query} #{condition} #{self.field} LIKE '%#{self.value}%'"
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ private
33
+ attr_accessor :field, :value
34
+ end
@@ -0,0 +1,26 @@
1
+ require_relative '../filter_decorator.rb'
2
+
3
+ class Full_name_filter_decorator < Filter_decorator
4
+ def initialize(filter, full_name)
5
+ super(filter)
6
+ self.full_name = full_name.strip.downcase unless full_name.nil?
7
+ end
8
+
9
+ def apply(filtering_obj)
10
+ return super(filtering_obj) if self.full_name.nil? || self.full_name.empty?
11
+
12
+ if filtering_obj.is_a?(Array)
13
+ super(filtering_obj).select do |student|
14
+ initials = "#{student.get_full_name}"
15
+ initials.downcase.include?(self.full_name)
16
+ end
17
+ else
18
+ query = super(filtering_obj)
19
+ condition = query.include?("WHERE") ? "AND" : "WHERE"
20
+ "#{query} #{condition} CONCAT(LOWER(first_name), ' ', LOWER(LEFT(name, 1)), '.', LOWER(LEFT(patronymic, 1)), '.') LIKE '%#{self.full_name}%'"
21
+ end
22
+ end
23
+
24
+ private
25
+ attr_accessor :full_name
26
+ end