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,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require './lib/repositories/containers/data_table'
|
4
|
+
|
5
|
+
class DataList
|
6
|
+
# Это "абстрактный" класс
|
7
|
+
private_class_method :new
|
8
|
+
|
9
|
+
attr_writer :objects
|
10
|
+
|
11
|
+
# Конструктор, принимает массив любых объектов
|
12
|
+
def initialize(objects)
|
13
|
+
self.objects = objects
|
14
|
+
@listeners = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_listener(listener)
|
18
|
+
@listeners << listener
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove_listener(listener)
|
22
|
+
@listeners.delete(listener)
|
23
|
+
end
|
24
|
+
|
25
|
+
def notify
|
26
|
+
@listeners.each { |lst| lst.on_datalist_changed(data_table) }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Выбрать элемент по номеру
|
30
|
+
def select_element(number)
|
31
|
+
self.selected_num = number < objects.size ? number : nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def selected_id
|
35
|
+
objects[selected_num].id
|
36
|
+
end
|
37
|
+
|
38
|
+
# Получить DataTable со всеми элементами.
|
39
|
+
def data_table
|
40
|
+
result = []
|
41
|
+
counter = 0
|
42
|
+
objects.each do |obj|
|
43
|
+
row = []
|
44
|
+
row << counter
|
45
|
+
row.push(*table_fields(obj))
|
46
|
+
result << row
|
47
|
+
counter += 1
|
48
|
+
end
|
49
|
+
DataTable.new(result)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Добавить элементы в конец списка
|
53
|
+
def replace_objects(objects)
|
54
|
+
self.objects = objects.dup
|
55
|
+
notify
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
# Список значений полей для DataTable. Переопределить в наследниках
|
61
|
+
def table_fields(_obj)
|
62
|
+
[]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Имена атрибутов объектов по порядку. Переопределить в наследниках
|
66
|
+
def column_names
|
67
|
+
[]
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
attr_reader :objects
|
73
|
+
attr_accessor :selected_num
|
74
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'data_list'
|
4
|
+
|
5
|
+
class DataListStudentShort < DataList
|
6
|
+
# Делаем приватный new предка публичным
|
7
|
+
public_class_method :new
|
8
|
+
|
9
|
+
def column_names
|
10
|
+
['Фамилия И. О.', 'Гит', 'Контакт']
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def table_fields(obj)
|
16
|
+
[obj.last_name_and_initials, obj.git, obj.contact]
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DataTable
|
4
|
+
attr_reader :rows_count, :cols_count
|
5
|
+
|
6
|
+
# Конструктор, принимает 2D Array
|
7
|
+
def initialize(table)
|
8
|
+
self.rows_count = table.size
|
9
|
+
max_cols = 0
|
10
|
+
table.each { |row| max_cols = row.size if row.size > max_cols }
|
11
|
+
self.cols_count = max_cols
|
12
|
+
self.table = table
|
13
|
+
end
|
14
|
+
|
15
|
+
# Получить значение в ячейке [row, col]
|
16
|
+
def get_item(row, col)
|
17
|
+
return nil if row >= rows_count
|
18
|
+
return nil if col >= cols_count
|
19
|
+
|
20
|
+
table[row][col].dup
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_2d_array
|
24
|
+
table.dup
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"DataTable (#{rows_count}x#{cols_count})"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_accessor :table
|
34
|
+
attr_writer :rows_count, :cols_count
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mysql2'
|
4
|
+
|
5
|
+
class DBDataSource
|
6
|
+
private_class_method :new
|
7
|
+
@instance_mutex = Mutex.new
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
db_config = YAML.load_file('./lib/db_config/config.yaml').transform_keys(&:to_sym)
|
11
|
+
@client = Mysql2::Client.new(db_config)
|
12
|
+
@client.query_options.merge!(symbolize_keys: true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.instance
|
16
|
+
return @instance if @instance
|
17
|
+
|
18
|
+
@instance_mutex.synchronize do
|
19
|
+
@instance ||= new
|
20
|
+
end
|
21
|
+
|
22
|
+
@instance
|
23
|
+
end
|
24
|
+
|
25
|
+
def prepare_exec(statement, *params)
|
26
|
+
@client.prepare(statement).execute(*params)
|
27
|
+
end
|
28
|
+
|
29
|
+
def query(statement)
|
30
|
+
@client.query(statement)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require './lib/models/student'
|
4
|
+
require './lib/models/student_short'
|
5
|
+
require './lib/repositories/containers/data_list_student_short'
|
6
|
+
|
7
|
+
class FileDataSource
|
8
|
+
attr_writer :data_transformer
|
9
|
+
|
10
|
+
def initialize(data_transformer)
|
11
|
+
self.students = []
|
12
|
+
self.seq_id = 1
|
13
|
+
self.data_transformer = data_transformer
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_from_file(file_path)
|
17
|
+
hash_list = data_transformer.str_to_hash_list(File.read(file_path))
|
18
|
+
self.students = hash_list.map { |h| Student.from_hash(h) }
|
19
|
+
update_seq_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def save_to_file(file_path)
|
23
|
+
hash_list = students.map(&:to_hash)
|
24
|
+
File.write(file_path, data_transformer.hash_list_to_str(hash_list))
|
25
|
+
end
|
26
|
+
|
27
|
+
def student_by_id(student_id)
|
28
|
+
students.detect { |s| s.id == student_id }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Получить page по счету count элементов (страница начинается с 1)
|
32
|
+
def paginated_short_students(page, count, existing_data_list = nil)
|
33
|
+
offset = (page - 1) * count
|
34
|
+
slice = students[offset, count].map { |s| StudentShort.from_student(s) }
|
35
|
+
|
36
|
+
return DataListStudentShort.new(slice) if existing_data_list.nil?
|
37
|
+
|
38
|
+
existing_data_list.replace_objects(slice)
|
39
|
+
existing_data_list
|
40
|
+
end
|
41
|
+
|
42
|
+
def sorted
|
43
|
+
students.sort_by(&:last_name_and_initials)
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_student(student)
|
47
|
+
student.id = seq_id
|
48
|
+
students << student
|
49
|
+
self.seq_id += 1
|
50
|
+
student.id
|
51
|
+
end
|
52
|
+
|
53
|
+
def replace_student(student_id, student)
|
54
|
+
idx = students.find_index { |s| s.id == student_id }
|
55
|
+
students[idx] = student
|
56
|
+
end
|
57
|
+
|
58
|
+
def remove_student(student_id)
|
59
|
+
students.reject! { |s| s.id == student_id }
|
60
|
+
end
|
61
|
+
|
62
|
+
def student_count
|
63
|
+
students.count
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Метод для актуализации seq_id
|
69
|
+
def update_seq_id
|
70
|
+
self.seq_id = students.max_by(&:id).id + 1
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_reader :data_transformer
|
74
|
+
attr_accessor :students, :seq_id
|
75
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DataTransformerBase
|
4
|
+
private_class_method :new
|
5
|
+
|
6
|
+
protected
|
7
|
+
|
8
|
+
def str_to_hash_list(str)
|
9
|
+
raise NotImplementedError('Should be implemented in child')
|
10
|
+
end
|
11
|
+
|
12
|
+
def hash_list_to_str(hash_list)
|
13
|
+
raise NotImplementedError('Should be implemented in child')
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'data_transformer_base'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class DataTransformerJSON < DataTransformerBase
|
7
|
+
public_class_method :new
|
8
|
+
|
9
|
+
def str_to_hash_list(str)
|
10
|
+
JSON.parse(str, { symbolize_names: true })
|
11
|
+
end
|
12
|
+
|
13
|
+
def hash_list_to_str(hash_list)
|
14
|
+
JSON.pretty_generate(hash_list)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'data_transformer_base'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
class DataTransformerYAML < DataTransformerBase
|
7
|
+
public_class_method :new
|
8
|
+
|
9
|
+
def str_to_hash_list(str)
|
10
|
+
YAML.safe_load(str).map { |h| h.transform_keys(&:to_sym) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def hash_list_to_str(hash_list)
|
14
|
+
hash_list.map { |h| h.transform_keys(&:to_s) }.to_yaml
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class StudentRepository
|
4
|
+
def initialize(data_source_adapter)
|
5
|
+
@data_source_adapter = data_source_adapter
|
6
|
+
end
|
7
|
+
|
8
|
+
def student_by_id(student_id)
|
9
|
+
@data_source_adapter.student_by_id(student_id)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Получить page по счету count элементов (страница начинается с 1)
|
13
|
+
def paginated_short_students(page, count, existing_data_list = nil)
|
14
|
+
@data_source_adapter.paginated_short_students(page, count, existing_data_list)
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_student(student)
|
18
|
+
@data_source_adapter.add_student(student)
|
19
|
+
end
|
20
|
+
|
21
|
+
def replace_student(student_id, student)
|
22
|
+
@data_source_adapter.replace_student(student_id, student)
|
23
|
+
end
|
24
|
+
|
25
|
+
def remove_student(student_id)
|
26
|
+
@data_source_adapter.remove_student(student_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
def student_count
|
30
|
+
@data_source_adapter.student_count
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class ListStateNotifier
|
2
|
+
attr_reader :items
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@items = []
|
6
|
+
@listeners = []
|
7
|
+
end
|
8
|
+
|
9
|
+
# устанавливает новое значение для items и уведомляет всех слушателей.
|
10
|
+
def set_all(objects)
|
11
|
+
LoggerHolder.instance.debug('ListStateNotifier: set_all')
|
12
|
+
@items = objects
|
13
|
+
notify_listeners
|
14
|
+
end
|
15
|
+
|
16
|
+
# добавляет объект в массив items и уведомляет всех слушателей.
|
17
|
+
def add(object)
|
18
|
+
LoggerHolder.instance.debug('ListStateNotifier: add')
|
19
|
+
@items << object
|
20
|
+
notify_listeners
|
21
|
+
end
|
22
|
+
# возвращает объект из массива items по индексу.
|
23
|
+
def get(number)
|
24
|
+
LoggerHolder.instance.debug('ListStateNotifier: get')
|
25
|
+
@items[number]
|
26
|
+
end
|
27
|
+
|
28
|
+
# удаляет объект из массива items и уведомляет всех слушателей.
|
29
|
+
def delete(object)
|
30
|
+
LoggerHolder.instance.debug('ListStateNotifier: delete')
|
31
|
+
@items.delete(object)
|
32
|
+
notify_listeners
|
33
|
+
end
|
34
|
+
|
35
|
+
# заменяет объект в массиве items на новый объект и уведомляет всех слушателей.
|
36
|
+
def replace(object, new_object)
|
37
|
+
LoggerHolder.instance.debug('ListStateNotifier: replace')
|
38
|
+
index = @items.index(object)
|
39
|
+
@items[index] = new_object
|
40
|
+
notify_listeners
|
41
|
+
end
|
42
|
+
# добавляет нового слушателя в массив listeners.
|
43
|
+
def add_listener(listener)
|
44
|
+
LoggerHolder.instance.debug('ListStateNotifier: add_listener')
|
45
|
+
@listeners << listener
|
46
|
+
end
|
47
|
+
# удаляет слушателя из массива listeners.
|
48
|
+
def delete_listener(listener)
|
49
|
+
LoggerHolder.instance.debug('ListStateNotifier: delete_listener')
|
50
|
+
@listeners.delete(listener)
|
51
|
+
end
|
52
|
+
|
53
|
+
# уведомляет всех слушателей о изменении массива items.
|
54
|
+
def notify_listeners
|
55
|
+
LoggerHolder.instance.debug('notify_listeners')
|
56
|
+
@listeners.each do |listener|
|
57
|
+
listener.update(@items)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'win32api'
|
3
|
+
|
4
|
+
class TaskInputFormControllerCreate
|
5
|
+
def initialize(parent_controller)
|
6
|
+
@parent_controller = parent_controller
|
7
|
+
@task_rep = TaskDbDataSource.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_view(view)
|
11
|
+
@view = view
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_view_created
|
15
|
+
# begin
|
16
|
+
# @student_rep = StudentRepository.new(DBSourceAdapter.new)
|
17
|
+
# rescue Mysql2::Error::ConnectionError
|
18
|
+
# on_db_conn_error
|
19
|
+
# end
|
20
|
+
end
|
21
|
+
|
22
|
+
def process_fields(fields)
|
23
|
+
begin
|
24
|
+
values = fields.values
|
25
|
+
values.insert(-2, Time.now.strftime("%Y-%m-%d"))
|
26
|
+
item = Task.new(-1, *values)
|
27
|
+
item = @task_rep.add(item)
|
28
|
+
@parent_controller.state_notifier.add(item)
|
29
|
+
@view.close
|
30
|
+
rescue ArgumentError => e
|
31
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
32
|
+
api.call(0, e.message, 'Error', 0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def on_db_conn_error
|
39
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
40
|
+
api.call(0, "No connection to DB", "Error", 0)
|
41
|
+
@view.close
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TaskInputFormControllerEdit
|
4
|
+
def initialize(parent_controller, item)
|
5
|
+
@parent_controller = parent_controller
|
6
|
+
@item = item
|
7
|
+
@task_rep = TaskDbDataSource.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_view(view)
|
11
|
+
@view = view
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_view_created
|
15
|
+
# begin
|
16
|
+
# @student_rep = StudentRepository.new(DBSourceAdapter.new)
|
17
|
+
# rescue Mysql2::Error::ConnectionError
|
18
|
+
# on_db_conn_error
|
19
|
+
# end
|
20
|
+
|
21
|
+
# @item = @author_rep.get(@item_id)
|
22
|
+
# @view.make_readonly(:git, :telegram, :email, :phone)
|
23
|
+
populate_fields(@item)
|
24
|
+
end
|
25
|
+
|
26
|
+
def populate_fields(item)
|
27
|
+
@view.set_value(:description, item.description)
|
28
|
+
@view.set_value(:completed, item.completed)
|
29
|
+
end
|
30
|
+
|
31
|
+
def process_fields(fields)
|
32
|
+
|
33
|
+
begin
|
34
|
+
print "\n"
|
35
|
+
print"ITEM ID=#{@item.task_id}"
|
36
|
+
print "\n"
|
37
|
+
item = Task.new(@item.task_id, @item.user_id, @item.manager_id, @item.date, *fields.values)
|
38
|
+
print "\n"
|
39
|
+
print"NEW ITEM ID=#{item.task_id}"
|
40
|
+
print "\n"
|
41
|
+
item = @task_rep.change(item)
|
42
|
+
@parent_controller.state_notifier.replace(@item, item)
|
43
|
+
@view.close
|
44
|
+
rescue ArgumentError => e
|
45
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
46
|
+
api.call(0, e.message, 'Error', 0)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def on_db_conn_error
|
53
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
54
|
+
api.call(0, "No connection to DB", "Error", 0)
|
55
|
+
@view.close
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require './lib/state_holders/list_state_notifier'
|
3
|
+
require_relative '../ui/task_input_form'
|
4
|
+
require_relative 'task_input_form_controller_create.rb'
|
5
|
+
require_relative 'task_input_form_controller_edit'
|
6
|
+
require_relative '../task_db_data_source'
|
7
|
+
require_relative '../ui/task_input_form_factory'
|
8
|
+
require 'win32api'
|
9
|
+
|
10
|
+
class TaskListController
|
11
|
+
|
12
|
+
attr_reader :state_notifier
|
13
|
+
def initialize(view)
|
14
|
+
@view = view
|
15
|
+
@state_notifier = ListStateNotifier.new
|
16
|
+
@state_notifier.add_listener(@view)
|
17
|
+
@task_rep = TaskDbDataSource.new
|
18
|
+
|
19
|
+
@sort_columns = %w[TaskID UserID ManagerID Date Description Completed]
|
20
|
+
@sort_by = @sort_columns.first
|
21
|
+
|
22
|
+
@completed_filter_columns = [nil, 'Done', 'Undone']
|
23
|
+
@completed_filter = @completed_filter_columns.first
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
def on_view_created
|
29
|
+
# begin
|
30
|
+
# @student_rep = StudentRepository.new(DBSourceAdapter.new)
|
31
|
+
# rescue Mysql2::Error::ConnectionError
|
32
|
+
# on_db_conn_error
|
33
|
+
# end
|
34
|
+
end
|
35
|
+
|
36
|
+
def show_view
|
37
|
+
@view.create.show
|
38
|
+
end
|
39
|
+
|
40
|
+
def show_modal_add
|
41
|
+
controller = TaskInputFormControllerCreate.new(self)
|
42
|
+
view = TaskInputFormFactory.create_create_form(controller)
|
43
|
+
controller.set_view(view)
|
44
|
+
view.create.show
|
45
|
+
end
|
46
|
+
|
47
|
+
def show_modal_edit(current_page, per_page, selected_row)
|
48
|
+
item = @state_notifier.get(selected_row)
|
49
|
+
controller = TaskInputFormControllerEdit.new(self, item)
|
50
|
+
view = TaskInputFormFactory.create_edit_form(controller, item)
|
51
|
+
controller.set_view(view)
|
52
|
+
view.create.show
|
53
|
+
end
|
54
|
+
|
55
|
+
def delete_selected(current_page, per_page, selected_row)
|
56
|
+
begin
|
57
|
+
item = @state_notifier.get(selected_row)
|
58
|
+
@task_rep.delete(item.task_id)
|
59
|
+
@state_notifier.delete(item)
|
60
|
+
rescue
|
61
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
62
|
+
api.call(0, "You cannot delete the user because he is associated with some user or manager", "Error", 0)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def refresh_data(page, per_page)
|
67
|
+
print "\n"
|
68
|
+
print "completed filter:#{@completed_filter}"
|
69
|
+
print "\n"
|
70
|
+
items = @task_rep.get_list(per_page, page, @sort_by, 'ASC', @completed_filter)
|
71
|
+
@state_notifier.set_all(items)
|
72
|
+
@view.update_student_count(@task_rep.count)
|
73
|
+
end
|
74
|
+
|
75
|
+
def sort(page, per_page, sort_index)
|
76
|
+
@sort_by = @sort_columns[sort_index]
|
77
|
+
refresh_data(page, per_page)
|
78
|
+
end
|
79
|
+
|
80
|
+
def filter_completed(page, per_page, filter_index)
|
81
|
+
@completed_filter = @completed_filter_columns[filter_index]
|
82
|
+
refresh_data(page, per_page)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def on_db_conn_error
|
89
|
+
api = Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I')
|
90
|
+
api.call(0, "No connection to DB", "Error", 0)
|
91
|
+
exit(false)
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'mysql2'
|
2
|
+
require_relative '../data_sources/db_client'
|
3
|
+
class TaskDbDataSource
|
4
|
+
def initialize
|
5
|
+
@client = DBClient.instance
|
6
|
+
end
|
7
|
+
def add(task)
|
8
|
+
user_exists = user_exists?(task.user_id)
|
9
|
+
manager_exists = manager_exists?(task.manager_id)
|
10
|
+
query = "INSERT INTO Task (UserID, ManagerID, Date, Description, Completed) VALUES (#{task.user_id}, #{task.manager_id}, '#{task.date}', '#{task.description}', '#{task.completed}')"
|
11
|
+
@client.query(query)
|
12
|
+
task_id = @client.last_id
|
13
|
+
get(task_id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def change(task)
|
17
|
+
user_exists = user_exists?(task.user_id)
|
18
|
+
manager_exists = manager_exists?(task.manager_id)
|
19
|
+
query = "UPDATE Task SET Completed='#{task.completed}', Description='#{task.description}' WHERE TaskID=#{task.task_id}"
|
20
|
+
@client.query(query)
|
21
|
+
get(task.task_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def delete(id)
|
26
|
+
query = "DELETE FROM Task WHERE TaskID=#{id}"
|
27
|
+
@client.query(query)
|
28
|
+
end
|
29
|
+
|
30
|
+
def get(id)
|
31
|
+
query = "SELECT * FROM Task WHERE TaskID=#{id}"
|
32
|
+
result = @client.query(query).first
|
33
|
+
if result
|
34
|
+
Task.new(result[:'TaskID'], result[:'UserID'], result[:'ManagerID'], result[:'Date'], result[:'Description'], result[:'Completed'])
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_list(page_size, page_num, sort_field, sort_direction, completed = nil)
|
41
|
+
offset = (page_num - 1) * page_size
|
42
|
+
query = "SELECT * FROM Task"
|
43
|
+
print "\n"
|
44
|
+
print "completed:#{completed}"
|
45
|
+
print "\n"
|
46
|
+
if completed == 'Done'
|
47
|
+
query += " WHERE Completed='Done'"
|
48
|
+
elsif completed == 'Undone'
|
49
|
+
query += " WHERE Completed='Undone'"
|
50
|
+
end
|
51
|
+
|
52
|
+
query += " ORDER BY #{sort_field} #{sort_direction} LIMIT #{page_size} OFFSET #{offset}"
|
53
|
+
results = @client.query(query)
|
54
|
+
|
55
|
+
tasks = []
|
56
|
+
results.each do |result|
|
57
|
+
tasks << Task.new(result[:'TaskID'], result[:'UserID'], result[:'ManagerID'], result[:'Date'], result[:'Description'], result[:'Completed'])
|
58
|
+
end
|
59
|
+
|
60
|
+
tasks
|
61
|
+
end
|
62
|
+
|
63
|
+
def count
|
64
|
+
query = "SELECT COUNT(*) FROM Task"
|
65
|
+
result = @client.query(query).first
|
66
|
+
result[:'COUNT(*)']
|
67
|
+
end
|
68
|
+
|
69
|
+
def user_exists?(user_id)
|
70
|
+
query = "SELECT COUNT(*) FROM User WHERE UserID=#{user_id}"
|
71
|
+
result = @client.query(query).first
|
72
|
+
unless result[:'COUNT(*)'] > 0
|
73
|
+
raise ArgumentError, "User with ID=#{user_id} doesn't exist"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def manager_exists?(manager_id)
|
78
|
+
query = "SELECT COUNT(*) FROM Manager WHERE ManagerID=#{manager_id}"
|
79
|
+
result = @client.query(query).first
|
80
|
+
unless result[:'COUNT(*)'] > 0
|
81
|
+
raise ArgumentError, "Manager with ID=#{manager_id} doesn't exist"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|