doto 0.0.1.pre.alpha.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 (179) hide show
  1. checksums.yaml +7 -0
  2. data/.env.test +1 -0
  3. data/.reek.yml +20 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +206 -0
  6. data/.ruby-version +1 -0
  7. data/CHANGELOG.md +7 -0
  8. data/CODE_OF_CONDUCT.md +84 -0
  9. data/Gemfile +30 -0
  10. data/Gemfile.lock +179 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +38 -0
  13. data/Rakefile +16 -0
  14. data/bin/console +36 -0
  15. data/bin/doto +3 -0
  16. data/bin/setup +18 -0
  17. data/exe/doto +33 -0
  18. data/lib/core/ruby/color_theme_colors.rb +16 -0
  19. data/lib/core/ruby/color_theme_mode.rb +42 -0
  20. data/lib/core/ruby/wrap_and_join.rb +31 -0
  21. data/lib/doto/base_cli.rb +56 -0
  22. data/lib/doto/cli.rb +131 -0
  23. data/lib/doto/command_services/add_entry_service.rb +50 -0
  24. data/lib/doto/crud/json_file.rb +161 -0
  25. data/lib/doto/env.rb +44 -0
  26. data/lib/doto/migration/base_service.rb +118 -0
  27. data/lib/doto/migration/migrator.rb +24 -0
  28. data/lib/doto/migration/raw_helpers/color_theme_hash.rb +13 -0
  29. data/lib/doto/migration/raw_helpers/configuration_hash.rb +15 -0
  30. data/lib/doto/migration/raw_helpers/entry_group_hash.rb +13 -0
  31. data/lib/doto/migration/raw_json_file.rb +15 -0
  32. data/lib/doto/migration/raw_json_files.rb +56 -0
  33. data/lib/doto/migration/v20230613121411/service.rb +94 -0
  34. data/lib/doto/migration/v20240210161248/service.rb +148 -0
  35. data/lib/doto/migration/version.rb +7 -0
  36. data/lib/doto/models/color_theme.rb +224 -0
  37. data/lib/doto/models/configuration.rb +185 -0
  38. data/lib/doto/models/entry.rb +63 -0
  39. data/lib/doto/models/entry_group.rb +223 -0
  40. data/lib/doto/models/migration_version.rb +49 -0
  41. data/lib/doto/models/project.rb +295 -0
  42. data/lib/doto/presenters/base_presenter.rb +32 -0
  43. data/lib/doto/presenters/base_presenter_ex.rb +15 -0
  44. data/lib/doto/presenters/color_theme_presenter.rb +52 -0
  45. data/lib/doto/presenters/color_theme_show_presenter.rb +55 -0
  46. data/lib/doto/presenters/configuration_presenter.rb +50 -0
  47. data/lib/doto/presenters/entry_group/list/date_presenter.rb +77 -0
  48. data/lib/doto/presenters/entry_group/list/dates_presenter.rb +60 -0
  49. data/lib/doto/presenters/entry_group/list/messages.rb +15 -0
  50. data/lib/doto/presenters/entry_group/list/nothing_to_list.rb +15 -0
  51. data/lib/doto/presenters/entry_group_presenter.rb +35 -0
  52. data/lib/doto/presenters/entry_presenter.rb +25 -0
  53. data/lib/doto/presenters/export/all_presenter.rb +44 -0
  54. data/lib/doto/presenters/export/dates_presenter.rb +55 -0
  55. data/lib/doto/presenters/import/all_presenter.rb +57 -0
  56. data/lib/doto/presenters/import/dates_presenter.rb +70 -0
  57. data/lib/doto/presenters/import/import_entry.rb +22 -0
  58. data/lib/doto/presenters/import/import_file.rb +33 -0
  59. data/lib/doto/presenters/project/create_presenter.rb +44 -0
  60. data/lib/doto/presenters/project/defaultable.rb +15 -0
  61. data/lib/doto/presenters/project/delete_by_number_presenter.rb +54 -0
  62. data/lib/doto/presenters/project/delete_presenter.rb +53 -0
  63. data/lib/doto/presenters/project/list_presenter.rb +24 -0
  64. data/lib/doto/presenters/project/rename_by_number_presenter.rb +63 -0
  65. data/lib/doto/presenters/project/rename_presenter.rb +57 -0
  66. data/lib/doto/presenters/project/use_by_number_presenter.rb +57 -0
  67. data/lib/doto/presenters/project/use_presenter.rb +56 -0
  68. data/lib/doto/services/color_theme/hydrator_service.rb +42 -0
  69. data/lib/doto/services/configuration/hydrator_service.rb +42 -0
  70. data/lib/doto/services/entry/hydrator_service.rb +33 -0
  71. data/lib/doto/services/entry_group/browse_service.rb +100 -0
  72. data/lib/doto/services/entry_group/counter_service.rb +32 -0
  73. data/lib/doto/services/entry_group/deleter_service.rb +35 -0
  74. data/lib/doto/services/entry_group/editor_service.rb +103 -0
  75. data/lib/doto/services/entry_group/exporter_service.rb +98 -0
  76. data/lib/doto/services/entry_group/hydrator_service.rb +37 -0
  77. data/lib/doto/services/entry_group/importer_service.rb +117 -0
  78. data/lib/doto/services/migration_version/hydrator_service.rb +36 -0
  79. data/lib/doto/services/project/hydrator_service.rb +40 -0
  80. data/lib/doto/services/project/rename_service.rb +70 -0
  81. data/lib/doto/services/stderr_redirector_service.rb +27 -0
  82. data/lib/doto/services/stdout_redirector_service.rb +27 -0
  83. data/lib/doto/services/temp_file/reader_service.rb +33 -0
  84. data/lib/doto/services/temp_file/writer_service.rb +35 -0
  85. data/lib/doto/subcommands/base_subcommand.rb +12 -0
  86. data/lib/doto/subcommands/browse.rb +49 -0
  87. data/lib/doto/subcommands/config.rb +81 -0
  88. data/lib/doto/subcommands/delete.rb +108 -0
  89. data/lib/doto/subcommands/edit.rb +48 -0
  90. data/lib/doto/subcommands/export.rb +62 -0
  91. data/lib/doto/subcommands/import.rb +72 -0
  92. data/lib/doto/subcommands/list.rb +95 -0
  93. data/lib/doto/subcommands/project.rb +146 -0
  94. data/lib/doto/subcommands/theme.rb +131 -0
  95. data/lib/doto/support/ask.rb +44 -0
  96. data/lib/doto/support/color_themable.rb +36 -0
  97. data/lib/doto/support/command_help_colorizeable.rb +34 -0
  98. data/lib/doto/support/command_hookable.rb +71 -0
  99. data/lib/doto/support/command_options/doto_times.rb +48 -0
  100. data/lib/doto/support/command_options/time.rb +84 -0
  101. data/lib/doto/support/command_options/time_mnemonic.rb +108 -0
  102. data/lib/doto/support/command_options/time_mnemonics.rb +16 -0
  103. data/lib/doto/support/descriptable.rb +29 -0
  104. data/lib/doto/support/entry_group_browsable.rb +104 -0
  105. data/lib/doto/support/field_errors.rb +11 -0
  106. data/lib/doto/support/fileable.rb +136 -0
  107. data/lib/doto/support/presentable.rb +11 -0
  108. data/lib/doto/support/project_file_system.rb +118 -0
  109. data/lib/doto/support/short_string.rb +24 -0
  110. data/lib/doto/support/time_comparable.rb +21 -0
  111. data/lib/doto/support/time_formatable.rb +65 -0
  112. data/lib/doto/support/times_sortable.rb +71 -0
  113. data/lib/doto/support/transform_project_name.rb +24 -0
  114. data/lib/doto/support/utils.rb +11 -0
  115. data/lib/doto/validators/color_theme_validator.rb +74 -0
  116. data/lib/doto/validators/description_validator.rb +51 -0
  117. data/lib/doto/validators/entries_validator.rb +77 -0
  118. data/lib/doto/validators/project_name_validator.rb +58 -0
  119. data/lib/doto/validators/time_validator.rb +25 -0
  120. data/lib/doto/validators/version_validator.rb +29 -0
  121. data/lib/doto/version.rb +6 -0
  122. data/lib/doto/views/base_list_view.rb +41 -0
  123. data/lib/doto/views/color_theme/index.rb +62 -0
  124. data/lib/doto/views/color_theme/show.rb +107 -0
  125. data/lib/doto/views/configuration/show.rb +41 -0
  126. data/lib/doto/views/entry_group/edit.rb +121 -0
  127. data/lib/doto/views/entry_group/list.rb +23 -0
  128. data/lib/doto/views/entry_group/shared/no_entries_to_display.rb +53 -0
  129. data/lib/doto/views/entry_group/shared/no_entries_to_display_for_month_of.rb +32 -0
  130. data/lib/doto/views/entry_group/shared/no_entries_to_display_for_week_of.rb +33 -0
  131. data/lib/doto/views/entry_group/shared/no_entries_to_display_for_year_of.rb +33 -0
  132. data/lib/doto/views/entry_group/show.rb +63 -0
  133. data/lib/doto/views/export.rb +82 -0
  134. data/lib/doto/views/import.rb +105 -0
  135. data/lib/doto/views/import_dates.rb +17 -0
  136. data/lib/doto/views/project/create.rb +87 -0
  137. data/lib/doto/views/project/delete.rb +96 -0
  138. data/lib/doto/views/project/delete_by_number.rb +19 -0
  139. data/lib/doto/views/project/list.rb +115 -0
  140. data/lib/doto/views/project/rename.rb +98 -0
  141. data/lib/doto/views/project/rename_by_number.rb +21 -0
  142. data/lib/doto/views/project/use.rb +97 -0
  143. data/lib/doto/views/project/use_by_number.rb +19 -0
  144. data/lib/doto/views/shared/error.rb +17 -0
  145. data/lib/doto/views/shared/info.rb +17 -0
  146. data/lib/doto/views/shared/message.rb +85 -0
  147. data/lib/doto/views/shared/model_errors.rb +32 -0
  148. data/lib/doto/views/shared/success.rb +17 -0
  149. data/lib/doto/views/shared/warning.rb +17 -0
  150. data/lib/doto.rb +33 -0
  151. data/lib/locales/en/active_record.yml +17 -0
  152. data/lib/locales/en/commands.yml +165 -0
  153. data/lib/locales/en/miscellaneous.yml +29 -0
  154. data/lib/locales/en/presenters.yml +19 -0
  155. data/lib/locales/en/services.yml +14 -0
  156. data/lib/locales/en/subcommands.yml +786 -0
  157. data/lib/seed_data/0/.todo +5 -0
  158. data/lib/seed_data/20230613121411/.doto +8 -0
  159. data/lib/seed_data/20230613121411/doto/migration_version.json +3 -0
  160. data/lib/seed_data/20230613121411/doto/themes/cherry.json +79 -0
  161. data/lib/seed_data/20230613121411/doto/themes/christmas.json +79 -0
  162. data/lib/seed_data/20230613121411/doto/themes/default.json +79 -0
  163. data/lib/seed_data/20230613121411/doto/themes/lemon.json +79 -0
  164. data/lib/seed_data/20230613121411/doto/themes/light.json +79 -0
  165. data/lib/seed_data/20230613121411/doto/themes/matrix.json +79 -0
  166. data/lib/seed_data/20230613121411/doto/themes/whiteout.json +79 -0
  167. data/lib/seed_data/20240210161248/.doto +9 -0
  168. data/lib/seed_data/20240210161248/doto/current_project.json +4 -0
  169. data/lib/seed_data/20240210161248/doto/migration_version.json +3 -0
  170. data/lib/seed_data/20240210161248/doto/projects/default/project.json +5 -0
  171. data/lib/seed_data/20240210161248/doto/themes/cherry.json +79 -0
  172. data/lib/seed_data/20240210161248/doto/themes/christmas.json +79 -0
  173. data/lib/seed_data/20240210161248/doto/themes/default.json +79 -0
  174. data/lib/seed_data/20240210161248/doto/themes/lemon.json +79 -0
  175. data/lib/seed_data/20240210161248/doto/themes/light.json +79 -0
  176. data/lib/seed_data/20240210161248/doto/themes/matrix.json +79 -0
  177. data/lib/seed_data/20240210161248/doto/themes/whiteout.json +79 -0
  178. data/sig/dsu.rbs +4 -0
  179. metadata +406 -0
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../support/time_formatable'
4
+ require_relative 'base_presenter'
5
+
6
+ module Doto
7
+ module Presenters
8
+ class EntryGroupPresenter < BasePresenter
9
+ attr_reader :entry_group
10
+
11
+ def initialize(entry_group, options: {})
12
+ super
13
+
14
+ @entry_group = entry_group
15
+ end
16
+
17
+ def formatted_time
18
+ colors = color_theme.date
19
+ apply_theme(Support::TimeFormatable.formatted_time(time: time), theme_color: colors)
20
+ end
21
+
22
+ def formatted_errors
23
+ return if valid?
24
+
25
+ colors = color_theme.error
26
+ apply_theme(errors.full_messages.join(', '), theme_color: colors)
27
+ end
28
+
29
+ def no_entries_available
30
+ header = I18n.t('presenters.entry_group_presenter.headers.no_entries_available')
31
+ apply_theme(header, theme_color: color_theme.info)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_presenter'
4
+
5
+ module Doto
6
+ module Presenters
7
+ class EntryPresenter < BasePresenter
8
+ attr_reader :entry
9
+
10
+ def initialize(entry, options: {})
11
+ super
12
+
13
+ @entry = entry
14
+ end
15
+
16
+ def formatted_description
17
+ apply_theme(description, theme_color: color_theme.body)
18
+ end
19
+
20
+ def formatted_description_with_index(index:)
21
+ "#{formatted_index(index: index)} #{formatted_description}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+ require_relative '../../services/entry_group/exporter_service'
5
+ require_relative '../base_presenter_ex'
6
+
7
+ module Doto
8
+ module Presenters
9
+ module Export
10
+ class AllPresenter < BasePresenterEx
11
+ attr_reader :export_file_path
12
+
13
+ def respond(response:)
14
+ return false unless response
15
+
16
+ @export_file_path = exporter_service.call
17
+ end
18
+
19
+ def nothing_to_export?
20
+ entry_group_count.zero?
21
+ end
22
+
23
+ def entry_group_count
24
+ entry_groups&.count || 0
25
+ end
26
+
27
+ private
28
+
29
+ def entry_groups
30
+ @entry_groups ||= Models::EntryGroup.all
31
+ end
32
+
33
+ def exporter_service
34
+ Services::EntryGroup::ExporterService.new(project_name: project_name,
35
+ entry_groups: entry_groups, options: options)
36
+ end
37
+
38
+ def project_name
39
+ @project_name ||= Models::Project.current_project.project_name
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+ require_relative '../../services/entry_group/exporter_service'
5
+ require_relative '../base_presenter_ex'
6
+
7
+ module Doto
8
+ module Presenters
9
+ module Export
10
+ class DatesPresenter < BasePresenterEx
11
+ attr_reader :export_file_path
12
+
13
+ def initialize(from:, to:, options: {})
14
+ super(options: options)
15
+
16
+ @from = from
17
+ @to = to
18
+
19
+ self.options[:times] = [from, to]
20
+ end
21
+
22
+ def respond(response:)
23
+ return false unless response
24
+
25
+ @export_file_path = exporter_service.call
26
+ end
27
+
28
+ def nothing_to_export?
29
+ entry_groups.empty?
30
+ end
31
+
32
+ def entry_group_count
33
+ entry_groups&.count || 0
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :from, :to, :options
39
+
40
+ def entry_groups
41
+ Models::EntryGroup.entry_groups(between: [from, to])
42
+ end
43
+
44
+ def exporter_service
45
+ Services::EntryGroup::ExporterService.new(project_name: project_name,
46
+ entry_groups: entry_groups, options: options)
47
+ end
48
+
49
+ def project_name
50
+ @project_name ||= Models::Project.current_project.project_name
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+ require_relative '../../services/entry_group/importer_service'
5
+ require_relative '../base_presenter_ex'
6
+ require_relative 'import_entry'
7
+ require_relative 'import_file'
8
+
9
+ module Doto
10
+ module Presenters
11
+ module Import
12
+ class AllPresenter < BasePresenterEx
13
+ include ImportEntry
14
+ include ImportFile
15
+
16
+ attr_reader :import_file_path, :import_messages
17
+
18
+ def initialize(import_file_path:, options: {})
19
+ super(options: options)
20
+
21
+ @import_file_path = import_file_path
22
+ end
23
+
24
+ def respond
25
+ @import_messages = importer_service.call
26
+ end
27
+
28
+ def project_name
29
+ @project_name ||= Models::Project.current_project.project_name
30
+ end
31
+
32
+ private
33
+
34
+ def import_entry_groups
35
+ @import_entry_groups ||= CSV.foreach(import_file_path,
36
+ headers: true, header_converters: :symbol).with_object({}) do |entry_group_entry, entry_groups_hash|
37
+ next unless import_entry?(entry_group_entry)
38
+
39
+ project_name = entry_group_entry[:project_name]
40
+ entry_groups_hash[project_name] = {} unless entry_groups_hash.key?(project_name)
41
+
42
+ Date.parse(entry_group_entry[:entry_group]).to_s.tap do |time|
43
+ entry_groups_hash[project_name][time] = [] unless entry_groups_hash[project_name].key?(time)
44
+ entry_groups_hash[project_name][time] << entry_group_entry[:entry_group_entry]
45
+ end
46
+ end
47
+ end
48
+
49
+ def importer_service
50
+ @importer_service ||= Services::EntryGroup::ImporterService.new(
51
+ import_projects: import_entry_groups, options: options
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/entry_group'
4
+ require_relative '../../services/entry_group/importer_service'
5
+ require_relative '../base_presenter_ex'
6
+ require_relative 'import_entry'
7
+ require_relative 'import_file'
8
+
9
+ module Doto
10
+ module Presenters
11
+ module Import
12
+ class DatesPresenter < BasePresenterEx
13
+ include ImportEntry
14
+ include ImportFile
15
+
16
+ attr_reader :from, :to, :import_file_path, :import_messages
17
+
18
+ def initialize(from:, to:, import_file_path:, options: {})
19
+ super(options: options)
20
+
21
+ @from = from.beginning_of_day
22
+ @to = to.end_of_day
23
+ @import_file_path = import_file_path
24
+ end
25
+
26
+ def respond
27
+ @import_messages = importer_service.call
28
+ end
29
+
30
+ def project_name
31
+ @project_name ||= Models::Project.current_project.project_name
32
+ end
33
+
34
+ private
35
+
36
+ def import_entry_groups
37
+ @import_entry_groups ||= CSV.foreach(import_file_path,
38
+ headers: true, header_converters: :symbol).with_object({}) do |entry_group_entry, entry_groups_hash|
39
+ next unless import_entry?(entry_group_entry)
40
+
41
+ entry_group_time = middle_of_day_for(entry_group_entry[:entry_group])
42
+ next unless time_between_to_and_from_dates?(entry_group_time)
43
+
44
+ project_name = entry_group_entry[:project_name]
45
+ entry_groups_hash[project_name] = {} unless entry_groups_hash.key?(project_name)
46
+
47
+ entry_group_time.to_date.to_s.tap do |time|
48
+ entry_groups_hash[project_name][time] = [] unless entry_groups_hash[project_name].key?(time)
49
+ entry_groups_hash[project_name][time] << entry_group_entry[:entry_group_entry]
50
+ end
51
+ end
52
+ end
53
+
54
+ def time_between_to_and_from_dates?(entry_group_time)
55
+ entry_group_time.to_date.between?(from.to_date, to.to_date)
56
+ end
57
+
58
+ def middle_of_day_for(date_string)
59
+ Time.parse(date_string).in_time_zone.middle_of_day
60
+ end
61
+
62
+ def importer_service
63
+ @importer_service ||= Services::EntryGroup::ImporterService.new(
64
+ import_projects: import_entry_groups, options: options
65
+ )
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../migration/version'
4
+
5
+ module Doto
6
+ module Presenters
7
+ module Import
8
+ module ImportEntry
9
+ def overriding_project?
10
+ options&.fetch(:override, false)
11
+ end
12
+
13
+ private
14
+
15
+ def import_entry?(entry_group_entry)
16
+ entry_group_entry[:version].to_i == Doto::Migration::VERSION &&
17
+ (overriding_project? || entry_group_entry[:project_name] == project_name)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doto
4
+ module Presenters
5
+ module Import
6
+ module ImportFile
7
+ def import_file_path_exist?
8
+ File.exist? import_file_path
9
+ end
10
+
11
+ def nothing_to_import?
12
+ return true unless import_file_path_exist?
13
+
14
+ import_entry_groups.count.zero?
15
+ end
16
+
17
+ def import_entry_groups
18
+ # Should return a Hash of entry group entries
19
+ # Example: { '2023-12-32' => ['Entry description 1', 'Entry description 2', ...] }
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def import_entry_groups_count
24
+ if overriding_project?
25
+ import_entry_groups&.first&.count || 0
26
+ else
27
+ import_entry_groups[project_name]&.count || 0
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/project'
4
+ require_relative '../base_presenter_ex'
5
+
6
+ module Doto
7
+ module Presenters
8
+ module Project
9
+ class CreatePresenter < BasePresenterEx
10
+ delegate :project_name, to: :project
11
+
12
+ def initialize(project_name:, description:, options: {})
13
+ super(options: options)
14
+
15
+ @project = Models::Project.new(project_name: project_name, description: description, options: options)
16
+ end
17
+
18
+ def respond(response:)
19
+ return false unless response
20
+
21
+ project.create!
22
+ end
23
+
24
+ def project_already_exists?
25
+ project.exist?
26
+ end
27
+
28
+ def project_errors?
29
+ project.invalid?
30
+ end
31
+
32
+ def project_errors
33
+ return [] unless project_errors?
34
+
35
+ project.errors.full_messages
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :project, :options
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doto
4
+ module Presenters
5
+ module Project
6
+ module Defaultable
7
+ private
8
+
9
+ def make_default?
10
+ options.fetch(:default, false)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/project'
4
+ require_relative '../base_presenter_ex'
5
+
6
+ module Doto
7
+ module Presenters
8
+ module Project
9
+ class DeleteByNumberPresenter < BasePresenterEx
10
+ attr_reader :project_number
11
+
12
+ delegate :project_name, to: :project, allow_nil: true
13
+ delegate :description, to: :project, prefix: true, allow_nil: true
14
+
15
+ def initialize(project_number:, options: {})
16
+ super(options: options)
17
+
18
+ raise ArgumentError, 'project_number is blank' if project_number.blank?
19
+
20
+ self.project_number = project_number
21
+ end
22
+
23
+ def respond(response:)
24
+ return false unless response
25
+ return false if project_does_not_exist? || project_default?
26
+
27
+ project.delete! if project&.present?
28
+ end
29
+
30
+ def project_does_not_exist?
31
+ !project&.exist?
32
+ end
33
+
34
+ def project_default?
35
+ project&.default_project?
36
+ end
37
+
38
+ def project_errors
39
+ return false unless project&.persisted?
40
+
41
+ project.errors.full_messages
42
+ end
43
+
44
+ private
45
+
46
+ attr_writer :project_number
47
+
48
+ def project
49
+ @project ||= Models::Project.find_by_number(project_number: project_number)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/project'
4
+ require_relative '../base_presenter_ex'
5
+
6
+ module Doto
7
+ module Presenters
8
+ module Project
9
+ class DeletePresenter < BasePresenterEx
10
+ attr_reader :project_name
11
+
12
+ delegate :description, to: :project, prefix: true, allow_nil: true
13
+
14
+ def initialize(project_name:, options: {})
15
+ super(options: options)
16
+
17
+ raise ArgumentError, 'project_name is blank' if project_name.blank?
18
+
19
+ self.project_name = project_name
20
+ end
21
+
22
+ def respond(response:)
23
+ return false unless response
24
+ return false if project_does_not_exist? || project_default?
25
+
26
+ project.delete! if project&.present?
27
+ end
28
+
29
+ def project_does_not_exist?
30
+ !project.exist?
31
+ end
32
+
33
+ def project_default?
34
+ project.default_project?
35
+ end
36
+
37
+ def project_errors
38
+ return false unless project.persisted?
39
+
40
+ project.errors.full_messages
41
+ end
42
+
43
+ private
44
+
45
+ attr_writer :project_name
46
+
47
+ def project
48
+ @project ||= Models::Project.find_or_initialize(project_name: project_name)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/project'
4
+ require_relative '../base_presenter_ex'
5
+
6
+ module Doto
7
+ module Presenters
8
+ module Project
9
+ class ListPresenter < BasePresenterEx
10
+ def initialize(options: {})
11
+ super
12
+ end
13
+
14
+ def projects
15
+ @projects ||= Doto::Models::Project.all
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :options
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/project'
4
+ require_relative '../base_presenter_ex'
5
+
6
+ module Doto
7
+ module Presenters
8
+ module Project
9
+ class RenameByNumberPresenter < BasePresenterEx
10
+ delegate :project_name, :description, to: :project, allow_nil: true
11
+
12
+ attr_reader :project_number
13
+
14
+ def initialize(project_number:, new_project_name:, new_project_description:, options: {})
15
+ super(options: options)
16
+
17
+ raise ArgumentError, 'project_number is blank' if project_number.blank?
18
+ raise ArgumentError, 'new_project_name is blank' if new_project_name.blank?
19
+
20
+ @project_number = project_number
21
+
22
+ @project = Models::Project.find_by_number(project_number: project_number)
23
+
24
+ @new_project = Models::Project.new(project_name: new_project_name.strip,
25
+ description: new_project_description&.strip, options: options).tap(&:validate)
26
+ end
27
+
28
+ def respond(response:)
29
+ return false unless response
30
+ return false if new_project.invalid?
31
+
32
+ project.rename!(new_project_name: new_project_name, new_project_description: new_project_description)
33
+ end
34
+
35
+ def project_does_not_exist?
36
+ return true unless project.present?
37
+
38
+ !project.exist?
39
+ end
40
+
41
+ def new_project_already_exists?
42
+ new_project.exist?
43
+ end
44
+
45
+ def new_project_name
46
+ new_project.project_name
47
+ end
48
+
49
+ def new_project_description
50
+ new_project.description
51
+ end
52
+
53
+ def new_project_errors
54
+ new_project.errors.full_messages
55
+ end
56
+
57
+ private
58
+
59
+ attr_reader :new_project, :project
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models/project'
4
+ require_relative '../base_presenter_ex'
5
+
6
+ module Doto
7
+ module Presenters
8
+ module Project
9
+ class RenamePresenter < BasePresenterEx
10
+ delegate :project_name, :description, to: :project
11
+
12
+ def initialize(project_name:, new_project_name:, new_project_description:, options: {})
13
+ super(options: options)
14
+
15
+ raise ArgumentError, 'project_name is blank' if project_name.blank?
16
+ raise ArgumentError, 'new_project_name is blank' if new_project_name.blank?
17
+
18
+ @project = Models::Project.find_or_initialize(project_name: project_name)
19
+
20
+ @new_project = Models::Project.new(project_name: new_project_name.strip,
21
+ description: new_project_description&.strip, options: options).tap(&:validate)
22
+ end
23
+
24
+ def respond(response:)
25
+ return false unless response
26
+ return false if new_project.invalid?
27
+
28
+ project.rename!(new_project_name: new_project_name, new_project_description: new_project_description)
29
+ end
30
+
31
+ def project_does_not_exist?
32
+ !project.exist?
33
+ end
34
+
35
+ def new_project_already_exists?
36
+ new_project.exist?
37
+ end
38
+
39
+ def new_project_name
40
+ new_project.project_name
41
+ end
42
+
43
+ def new_project_description
44
+ new_project.description
45
+ end
46
+
47
+ def new_project_errors
48
+ new_project.errors.full_messages
49
+ end
50
+
51
+ private
52
+
53
+ attr_reader :new_project, :project
54
+ end
55
+ end
56
+ end
57
+ end