papaSquidLib 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.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +69 -0
- data/lib/controllers/tab_students_controller.rb +43 -0
- data/lib/data_sources/db_client.rb +35 -0
- data/lib/db_config/config.yaml +5 -0
- data/lib/db_config/library_config.yaml +5 -0
- data/lib/db_config/migrations/create_db.sql +3 -0
- data/lib/db_config/migrations/create_tables.sql +29 -0
- data/lib/db_config/mock_data/mock_data.sql +72 -0
- data/lib/logger.rb +27 -0
- data/lib/main.rb +6 -0
- data/lib/manager/controllers/manager_input_form_controller_create.rb +44 -0
- data/lib/manager/controllers/manager_input_form_controller_edit.rb +54 -0
- data/lib/manager/controllers/manager_list_controller.rb +99 -0
- data/lib/manager/manager_db_data_source.rb +63 -0
- data/lib/manager/ui/manager_input_form.rb +69 -0
- data/lib/manager/ui/manager_list_view.rb +168 -0
- data/lib/models/manager.rb +41 -0
- data/lib/models/student.rb +102 -0
- data/lib/models/student_base.rb +100 -0
- data/lib/models/student_short.rb +50 -0
- data/lib/models/task.rb +49 -0
- data/lib/models/user.rb +32 -0
- data/lib/papaSquidLib/version.rb +5 -0
- data/lib/papa_squid_lib.rb +6 -0
- data/lib/repositories/adapters/db_source_adapter.rb +54 -0
- data/lib/repositories/adapters/file_source_adapter.rb +37 -0
- data/lib/repositories/containers/data_list.rb +74 -0
- data/lib/repositories/containers/data_list_student_short.rb +18 -0
- data/lib/repositories/containers/data_table.rb +35 -0
- data/lib/repositories/data_sources/db_data_source.rb +32 -0
- data/lib/repositories/data_sources/file_data_source.rb +75 -0
- data/lib/repositories/data_sources/transformers/data_transformer_base.rb +15 -0
- data/lib/repositories/data_sources/transformers/data_transformer_json.rb +16 -0
- data/lib/repositories/data_sources/transformers/data_transformer_yaml.rb +16 -0
- data/lib/repositories/student_repository.rb +32 -0
- data/lib/state_holders/list_state_notifier.rb +60 -0
- data/lib/task/controllers/task_input_form_controller_create.rb +43 -0
- data/lib/task/controllers/task_input_form_controller_edit.rb +57 -0
- data/lib/task/controllers/task_list_controller.rb +93 -0
- data/lib/task/task_db_data_source.rb +85 -0
- data/lib/task/ui/task_input_form.rb +67 -0
- data/lib/task/ui/task_input_form_factory.rb +26 -0
- data/lib/task/ui/task_list_view.rb +163 -0
- data/lib/user/controllers/user_input_form_controller_create.rb +42 -0
- data/lib/user/controllers/user_input_form_controller_edit.rb +53 -0
- data/lib/user/controllers/user_list_controller.rb +99 -0
- data/lib/user/ui/user_input_form.rb +69 -0
- data/lib/user/ui/user_list_view.rb +170 -0
- data/lib/user/user_db_data_source.rb +71 -0
- data/lib/views/main_window.rb +32 -0
- data/lib/views/tab_students.rb +148 -0
- data/papaSquidLib.gemspec +15 -0
- data/test/manager_test.rb +27 -0
- data/test/state_notifier_test.rb +82 -0
- data/test/task_test.rb +51 -0
- data/test/user_test.rb +39 -0
- metadata +113 -0
@@ -0,0 +1,168 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'glimmer-dsl-libui'
|
4
|
+
require_relative '../controllers/manager_list_controller'
|
5
|
+
require_relative 'manager_input_form'
|
6
|
+
|
7
|
+
class ManagerListView
|
8
|
+
include Glimmer
|
9
|
+
|
10
|
+
PAGE_SIZE = 20
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@controller = ManagerListController.new(self)
|
14
|
+
@current_page = 1
|
15
|
+
@total_count = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_create
|
19
|
+
@controller.on_view_created
|
20
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Метод наблюдателя datalist
|
24
|
+
# def on_datalist_changed(new_table)
|
25
|
+
# arr = new_table.to_2d_array
|
26
|
+
# arr.map do |row|
|
27
|
+
# row[3] = [row[3][:value], contact_color(row[3][:type])] unless row[3].nil?
|
28
|
+
# end
|
29
|
+
# @table.model_array = arr
|
30
|
+
# end
|
31
|
+
|
32
|
+
def update(managers)
|
33
|
+
@items = []
|
34
|
+
i = 0
|
35
|
+
item_num = 0
|
36
|
+
managers.each do |manager|
|
37
|
+
i += 1
|
38
|
+
item_num = ((@current_page - 1) * PAGE_SIZE) + i
|
39
|
+
@items << Struct.new(:№, :id, :имя, :почта, :телефон).new(item_num, manager.id, manager.name, manager.email, manager.phone)
|
40
|
+
end
|
41
|
+
|
42
|
+
@table.model_array = @items
|
43
|
+
@page_label.text = "#{@current_page} / #{(@total_count / PAGE_SIZE.to_f).ceil}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_student_count(new_cnt)
|
47
|
+
@total_count = new_cnt
|
48
|
+
@page_label.text = "#{@current_page} / #{(@total_count / PAGE_SIZE.to_f).ceil}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def create
|
52
|
+
|
53
|
+
root_container = horizontal_box {
|
54
|
+
# Секция 1
|
55
|
+
vertical_box {
|
56
|
+
stretchy false
|
57
|
+
|
58
|
+
vertical_box {
|
59
|
+
stretchy false
|
60
|
+
|
61
|
+
label {
|
62
|
+
text 'Почта'
|
63
|
+
}
|
64
|
+
combobox { |c|
|
65
|
+
items ['Не важно','Есть','Нет']
|
66
|
+
selected 0
|
67
|
+
on_selected do
|
68
|
+
@controller.filter_email(@current_page, PAGE_SIZE, c.selected)
|
69
|
+
end
|
70
|
+
}
|
71
|
+
|
72
|
+
label {
|
73
|
+
text 'Сортировка'
|
74
|
+
}
|
75
|
+
combobox { |c|
|
76
|
+
items ['ID','Название','Почта','Телефон']
|
77
|
+
selected 0
|
78
|
+
on_selected do
|
79
|
+
@controller.sort(@current_page, PAGE_SIZE, c.selected)
|
80
|
+
end
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
}
|
86
|
+
|
87
|
+
# Секция 2
|
88
|
+
vertical_box {
|
89
|
+
@table = refined_table(
|
90
|
+
table_editable: false,
|
91
|
+
filter: lambda do |row_hash, query|
|
92
|
+
utf8_query = query.force_encoding("utf-8")
|
93
|
+
row_hash['Имя пользователя'].include?(utf8_query)
|
94
|
+
end,
|
95
|
+
table_columns: {
|
96
|
+
'№' => :text,
|
97
|
+
'ID' => :text,
|
98
|
+
'Имя' => :text,
|
99
|
+
'Почта' => :text,
|
100
|
+
'Телефон' => :text,
|
101
|
+
},
|
102
|
+
per_page: PAGE_SIZE,
|
103
|
+
|
104
|
+
)
|
105
|
+
|
106
|
+
@pages = horizontal_box {
|
107
|
+
stretchy false
|
108
|
+
|
109
|
+
button("<") {
|
110
|
+
stretchy true
|
111
|
+
|
112
|
+
on_clicked do
|
113
|
+
@current_page = [@current_page - 1, 1].max
|
114
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
115
|
+
end
|
116
|
+
|
117
|
+
}
|
118
|
+
@page_label = label("...") { stretchy false }
|
119
|
+
button(">") {
|
120
|
+
stretchy true
|
121
|
+
|
122
|
+
on_clicked do
|
123
|
+
@current_page = [@current_page + 1, (@total_count / PAGE_SIZE.to_f).ceil].min
|
124
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
125
|
+
end
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
# Секция 3
|
131
|
+
vertical_box {
|
132
|
+
stretchy false
|
133
|
+
|
134
|
+
button('Добавить') {
|
135
|
+
stretchy false
|
136
|
+
|
137
|
+
on_clicked {
|
138
|
+
@controller.show_modal_add
|
139
|
+
}
|
140
|
+
}
|
141
|
+
button('Изменить') {
|
142
|
+
stretchy false
|
143
|
+
|
144
|
+
on_clicked {
|
145
|
+
@controller.show_modal_edit(@current_page, PAGE_SIZE, @table.selection) unless @table.selection.nil?
|
146
|
+
}
|
147
|
+
}
|
148
|
+
button('Удалить') {
|
149
|
+
stretchy false
|
150
|
+
|
151
|
+
on_clicked {
|
152
|
+
@controller.delete_selected(@current_page, PAGE_SIZE, @table.selection) unless @table.selection.nil?
|
153
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
154
|
+
}
|
155
|
+
}
|
156
|
+
button('Обновить') {
|
157
|
+
stretchy false
|
158
|
+
|
159
|
+
on_clicked {
|
160
|
+
@controller.refresh_data(@current_page, PAGE_SIZE)
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
165
|
+
on_create
|
166
|
+
root_container
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Manager
|
4
|
+
attr_accessor :id, :name, :email, :phone
|
5
|
+
|
6
|
+
def initialize(id, name, email, phone)
|
7
|
+
validate_null("name", name)
|
8
|
+
validate_null("email", email)
|
9
|
+
validate_null("phone", phone)
|
10
|
+
|
11
|
+
@id = id
|
12
|
+
@name = name
|
13
|
+
@email = email
|
14
|
+
@phone = phone
|
15
|
+
|
16
|
+
unless valid_email?
|
17
|
+
raise ArgumentError, "Invalid email format"
|
18
|
+
end
|
19
|
+
|
20
|
+
unless valid_phone?
|
21
|
+
raise ArgumentError, "Invalid phone number format"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def validate_null(name, value)
|
26
|
+
if value.nil?
|
27
|
+
raise ArgumentError, "Argument '#{name}' cannot be null"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid_email?
|
32
|
+
email_regex = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
|
33
|
+
!!(email =~ email_regex)
|
34
|
+
end
|
35
|
+
|
36
|
+
def valid_phone?
|
37
|
+
phone_regex = /\A(\+7|8)\s?\(?\d{3}\)?\s?\d{3}[\s-]?\d{2}[\s-]?\d{2}\z/
|
38
|
+
!!(phone =~ phone_regex)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require_relative 'student_base'
|
5
|
+
|
6
|
+
class Student < StudentBase
|
7
|
+
# Делаем new предка публичным
|
8
|
+
public_class_method :new
|
9
|
+
|
10
|
+
def self.from_hash(hash)
|
11
|
+
raise ArgumentError, 'Fields required: fist_name, last_name, father_name' unless hash.key?(:first_name) && hash.key?(:last_name) && hash.key?(:father_name)
|
12
|
+
|
13
|
+
first_name = hash.delete(:first_name)
|
14
|
+
last_name = hash.delete(:last_name)
|
15
|
+
father_name = hash.delete(:father_name)
|
16
|
+
|
17
|
+
Student.new(last_name, first_name, father_name, **hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Конструктор из JSON строки
|
21
|
+
def self.from_json_str(str)
|
22
|
+
params = JSON.parse(str, { symbolize_names: true })
|
23
|
+
from_hash(params)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Делаем публичными геттеры и сеттеры базового класса
|
27
|
+
public :phone, :telegram, :email, 'id=', 'phone=', 'telegram=', 'email=', 'git='
|
28
|
+
|
29
|
+
# Стандартные геттеры для полей
|
30
|
+
attr_reader :last_name, :first_name, :father_name
|
31
|
+
|
32
|
+
# Стандартный конструктор
|
33
|
+
def initialize(last_name, first_name, father_name, **options)
|
34
|
+
self.last_name = last_name
|
35
|
+
self.first_name = first_name
|
36
|
+
self.father_name = father_name
|
37
|
+
super(**options)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Сеттеры с валидацией перед присваиванием
|
41
|
+
def last_name=(new_last_name)
|
42
|
+
raise ArgumentError, "Invalid argument: last_name=#{new_last_name}" unless Student.valid_name?(new_last_name)
|
43
|
+
|
44
|
+
@last_name = new_last_name
|
45
|
+
end
|
46
|
+
|
47
|
+
def first_name=(new_first_name)
|
48
|
+
raise ArgumentError, "Invalid argument: first_name=#{new_first_name}" unless Student.valid_name?(new_first_name)
|
49
|
+
|
50
|
+
@first_name = new_first_name
|
51
|
+
end
|
52
|
+
|
53
|
+
def father_name=(new_father_name)
|
54
|
+
raise ArgumentError, "Invalid argument: father_name=#{new_father_name}" unless Student.valid_name?(new_father_name)
|
55
|
+
|
56
|
+
@father_name = new_father_name
|
57
|
+
end
|
58
|
+
|
59
|
+
# Отдельный сеттер для массовой установки контактов
|
60
|
+
def set_contacts(phone: nil, telegram: nil, email: nil)
|
61
|
+
self.phone = phone if phone
|
62
|
+
self.telegram = telegram if telegram
|
63
|
+
self.email = email if email
|
64
|
+
end
|
65
|
+
|
66
|
+
# Имя пользователя в формате Фамилия И. О.
|
67
|
+
def last_name_and_initials
|
68
|
+
"#{last_name} #{first_name[0]}. #{father_name[0]}."
|
69
|
+
end
|
70
|
+
|
71
|
+
# Краткая информация о пользователе
|
72
|
+
def short_info
|
73
|
+
info = {}
|
74
|
+
info[:last_name_and_initials] = last_name_and_initials
|
75
|
+
info[:contact] = short_contact
|
76
|
+
info[:git] = git
|
77
|
+
JSON.generate(info)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Методы приведения объекта к строке
|
81
|
+
def to_s
|
82
|
+
result = "#{last_name} #{first_name} #{father_name}"
|
83
|
+
%i[id phone telegram email git].each do |attr|
|
84
|
+
attr_val = send(attr)
|
85
|
+
result += ", #{attr}=#{attr_val}" unless attr_val.nil?
|
86
|
+
end
|
87
|
+
result
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_hash
|
91
|
+
attrs = {}
|
92
|
+
%i[last_name first_name father_name id phone telegram email git].each do |attr|
|
93
|
+
attr_val = send(attr)
|
94
|
+
attrs[attr] = attr_val unless attr_val.nil?
|
95
|
+
end
|
96
|
+
attrs
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_json_str
|
100
|
+
JSON.generate(to_hash)
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class StudentBase
|
4
|
+
# Запрещаем создание базового класса (он "абстрактный")
|
5
|
+
private_class_method :new
|
6
|
+
|
7
|
+
# Валидаторы для полей
|
8
|
+
def self.valid_name?(name)
|
9
|
+
name.match(/(^[А-Я][а-я]+$)|(^[A-Z][a-z]+$)/)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.valid_phone?(phone)
|
13
|
+
phone.match(/^\+?[78] ?[(-]?\d{3} ?[)-]?[ -]?\d{3}[ -]?\d{2}[ -]?\d{2}$/)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.valid_profile_name?(profile_name)
|
17
|
+
profile_name.match(/^[a-zA-Z0-9_.]+$/)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.valid_email?(email)
|
21
|
+
email.match(/^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Стандартные геттеры и сеттеры для полей
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
attr_writer :id
|
29
|
+
attr_reader :phone, :telegram, :email
|
30
|
+
|
31
|
+
public
|
32
|
+
|
33
|
+
attr_reader :id, :git
|
34
|
+
|
35
|
+
# Стандартный конструктор
|
36
|
+
def initialize(id: nil, phone: nil, telegram: nil, email: nil, git: nil)
|
37
|
+
self.id = id
|
38
|
+
self.phone = phone
|
39
|
+
self.telegram = telegram
|
40
|
+
self.email = email
|
41
|
+
self.git = git
|
42
|
+
end
|
43
|
+
|
44
|
+
# Краткая информация о первом доступном контакте пользователя
|
45
|
+
def short_contact
|
46
|
+
contact = {}
|
47
|
+
%i[telegram email phone].each do |attr|
|
48
|
+
attr_val = send(attr)
|
49
|
+
next if attr_val.nil?
|
50
|
+
|
51
|
+
contact[:type] = attr
|
52
|
+
contact[:value] = attr_val
|
53
|
+
return contact
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
# Сеттеры с валидацией перед присваиванием
|
62
|
+
def phone=(new_phone)
|
63
|
+
raise ArgumentError, "Invalid argument: phone=#{new_phone}" unless new_phone.nil? || StudentBase.valid_phone?(new_phone)
|
64
|
+
|
65
|
+
@phone = new_phone
|
66
|
+
end
|
67
|
+
|
68
|
+
def telegram=(new_telegram)
|
69
|
+
raise ArgumentError, "Invalid argument: telegram=#{new_telegram}" unless new_telegram.nil? || StudentBase.valid_profile_name?(new_telegram)
|
70
|
+
|
71
|
+
@telegram = new_telegram
|
72
|
+
end
|
73
|
+
|
74
|
+
def git=(new_git)
|
75
|
+
raise ArgumentError, "Invalid argument: git=#{new_git}" unless new_git.nil? || StudentBase.valid_profile_name?(new_git)
|
76
|
+
|
77
|
+
@git = new_git
|
78
|
+
end
|
79
|
+
|
80
|
+
def email=(new_email)
|
81
|
+
raise ArgumentError, "Invalid argument: email=#{new_email}" unless new_email.nil? || StudentBase.valid_email?(new_email)
|
82
|
+
|
83
|
+
@email = new_email
|
84
|
+
end
|
85
|
+
|
86
|
+
public
|
87
|
+
|
88
|
+
# Валидаторы объекта
|
89
|
+
def has_contacts?
|
90
|
+
!phone.nil? || !telegram.nil? || !email.nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
def has_git?
|
94
|
+
!git.nil?
|
95
|
+
end
|
96
|
+
|
97
|
+
def valid?
|
98
|
+
has_contacts? && has_git?
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class StudentShort < StudentBase
|
4
|
+
# Делаем new предка публичным
|
5
|
+
public_class_method :new
|
6
|
+
|
7
|
+
# Стандартные геттеры и сеттеры
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
attr_writer :last_name_and_initials, :contact
|
12
|
+
|
13
|
+
public
|
14
|
+
|
15
|
+
attr_reader :last_name_and_initials, :contact
|
16
|
+
|
17
|
+
# Конструктор из Student
|
18
|
+
def self.from_student(student)
|
19
|
+
raise ArgumentError, 'Student ID is required' if student.id.nil?
|
20
|
+
|
21
|
+
StudentShort.new(student.id, student.short_info)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Стандартный конструктор
|
25
|
+
def initialize(id, info_str)
|
26
|
+
params = JSON.parse(info_str, { symbolize_names: true })
|
27
|
+
raise ArgumentError, 'Fields required: last_name_and_initials' if !params.key?(:last_name_and_initials) || params[:last_name_and_initials].nil?
|
28
|
+
|
29
|
+
self.id = id
|
30
|
+
self.last_name_and_initials = params[:last_name_and_initials]
|
31
|
+
self.contact = params[:contact]
|
32
|
+
self.git = params[:git]
|
33
|
+
|
34
|
+
options = {}
|
35
|
+
options[:id] = id
|
36
|
+
options[:git] = git
|
37
|
+
options[contact[:type].to_sym] = contact[:value] if contact
|
38
|
+
super(**options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Методы приведения объекта к строке
|
42
|
+
def to_s
|
43
|
+
result = last_name_and_initials
|
44
|
+
%i[id contact git].each do |attr|
|
45
|
+
attr_val = send(attr)
|
46
|
+
result += ", #{attr}=#{attr_val}" unless attr_val.nil?
|
47
|
+
end
|
48
|
+
result
|
49
|
+
end
|
50
|
+
end
|
data/lib/models/task.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
class Task
|
2
|
+
attr_reader :task_id, :completed, :user_id, :date, :description, :manager_id
|
3
|
+
|
4
|
+
def initialize(task_id, user_id, manager_id, date = set_system_date, description = nil, completed = 'Undone')
|
5
|
+
validate_null('task_id', task_id)
|
6
|
+
validate_null('user_id', user_id)
|
7
|
+
validate_null('manager_id', manager_id)
|
8
|
+
|
9
|
+
validate_completed(completed)
|
10
|
+
|
11
|
+
@task_id = task_id
|
12
|
+
@user_id = user_id
|
13
|
+
@manager_id = manager_id
|
14
|
+
@date = date
|
15
|
+
@description = description
|
16
|
+
@completed = completed
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
{
|
22
|
+
task_id: task_id,
|
23
|
+
user_id: user_id,
|
24
|
+
manager_id: manager_id,
|
25
|
+
date: date,
|
26
|
+
description: description,
|
27
|
+
completed: completed
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_null(name, value)
|
34
|
+
if value.nil?
|
35
|
+
raise ArgumentError, "Argument '#{name}' cannot be null"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_system_date
|
40
|
+
Time.now.strftime("%Y-%m-%d")
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate_completed(completed)
|
44
|
+
unless completed == 'Done' || completed == 'Undone' || completed == 'Process'
|
45
|
+
raise ArgumentError, "Argument '#{completed}' can only be Done, Undone or Process"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/lib/models/user.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
class User
|
2
|
+
attr_reader :user_id, :first_name, :last_name, :father_name
|
3
|
+
|
4
|
+
def initialize(user_id, first_name, last_name, father_name = nil)
|
5
|
+
validate_null('user_id', user_id)
|
6
|
+
validate_null('first_name', first_name)
|
7
|
+
validate_null('last_name', last_name)
|
8
|
+
|
9
|
+
validate_name_length(first_name, last_name, father_name)
|
10
|
+
|
11
|
+
@user_id = user_id
|
12
|
+
@first_name = first_name
|
13
|
+
@last_name = last_name
|
14
|
+
@father_name = father_name
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def validate_null(name, value)
|
20
|
+
if value.nil?
|
21
|
+
raise ArgumentError, "Argument '#{name}' cannot be null"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def validate_name_length(first_name, last_name, father_name)
|
26
|
+
[first_name, last_name, father_name].each do |name|
|
27
|
+
if name && name.length > 50
|
28
|
+
raise ArgumentError, "Name exceeds 50 characters limit: #{name}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require './lib/repositories/data_sources/db_data_source'
|
4
|
+
require './lib/models/student'
|
5
|
+
require './lib/models/student_short'
|
6
|
+
require './lib/repositories/containers/data_list_student_short'
|
7
|
+
|
8
|
+
class DBSourceAdapter
|
9
|
+
def initialize
|
10
|
+
@db = DBDataSource.instance
|
11
|
+
end
|
12
|
+
|
13
|
+
def student_by_id(student_id)
|
14
|
+
hash = @db.prepare_exec('SELECT * FROM student WHERE id = ?', student_id).first
|
15
|
+
return nil if hash.nil?
|
16
|
+
|
17
|
+
Student.from_hash(hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
def paginated_short_students(page, count, existing_data_list = nil)
|
21
|
+
offset = (page - 1) * count
|
22
|
+
students = @db.prepare_exec('SELECT * FROM student LIMIT ?, ?', offset, count)
|
23
|
+
slice = students.map { |h| StudentShort.from_student(Student.from_hash(h)) }
|
24
|
+
return DataListStudentShort.new(slice) if existing_data_list.nil?
|
25
|
+
|
26
|
+
existing_data_list.replace_objects(slice)
|
27
|
+
existing_data_list
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_student(student)
|
31
|
+
template = 'INSERT INTO student(last_name, first_name, father_name, phone, telegram, email, git) VALUES (?, ?, ?, ?, ?, ?, ?)'
|
32
|
+
@db.prepare_exec(template, *student_fields(student))
|
33
|
+
@db.query('SELECT LAST_INSERT_ID()').first.first[1]
|
34
|
+
end
|
35
|
+
|
36
|
+
def replace_student(student_id, student)
|
37
|
+
template = 'UPDATE student SET last_name=?, first_name=?, father_name=?, phone=?, telegram=?, email=?, git=? WHERE id=?'
|
38
|
+
@db.prepare_exec(template, *student_fields(student), student_id)
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove_student(student_id)
|
42
|
+
@db.prepare_exec('DELETE FROM student WHERE id = ?', student_id)
|
43
|
+
end
|
44
|
+
|
45
|
+
def student_count
|
46
|
+
@db.query('SELECT COUNT(id) FROM student').first.first[1]
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def student_fields(student)
|
52
|
+
[student.last_name, student.first_name, student.father_name, student.phone, student.telegram, student.email, student.git]
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class FileSourceAdapter
|
4
|
+
def initialize(data_transformer, file_path)
|
5
|
+
@file_path = file_path
|
6
|
+
@file_source = FileDataSource.new(data_transformer)
|
7
|
+
@file_source.load_from_file(file_path)
|
8
|
+
end
|
9
|
+
|
10
|
+
def student_by_id(student_id)
|
11
|
+
@file_source.student_by_id(student_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
def paginated_short_students(page, count, existing_data_list = nil)
|
15
|
+
@file_source.paginated_short_students(page, count, existing_data_list)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_student(student)
|
19
|
+
added_id = @file_source.add_student(student)
|
20
|
+
@file_source.save_to_file(@file_path)
|
21
|
+
added_id
|
22
|
+
end
|
23
|
+
|
24
|
+
def replace_student(student_id, student)
|
25
|
+
@file_source.replace_student(student_id, student)
|
26
|
+
@file_source.save_to_file(@file_path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove_student(student_id)
|
30
|
+
@file_source.remove_student(student_id)
|
31
|
+
@file_source.save_to_file(@file_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def student_count
|
35
|
+
@file_source.student_count
|
36
|
+
end
|
37
|
+
end
|