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.
- checksums.yaml +7 -0
- data/.env.test +1 -0
- data/.reek.yml +20 -0
- data/.rspec +3 -0
- data/.rubocop.yml +206 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +30 -0
- data/Gemfile.lock +179 -0
- data/LICENSE.txt +21 -0
- data/README.md +38 -0
- data/Rakefile +16 -0
- data/bin/console +36 -0
- data/bin/doto +3 -0
- data/bin/setup +18 -0
- data/exe/doto +33 -0
- data/lib/core/ruby/color_theme_colors.rb +16 -0
- data/lib/core/ruby/color_theme_mode.rb +42 -0
- data/lib/core/ruby/wrap_and_join.rb +31 -0
- data/lib/doto/base_cli.rb +56 -0
- data/lib/doto/cli.rb +131 -0
- data/lib/doto/command_services/add_entry_service.rb +50 -0
- data/lib/doto/crud/json_file.rb +161 -0
- data/lib/doto/env.rb +44 -0
- data/lib/doto/migration/base_service.rb +118 -0
- data/lib/doto/migration/migrator.rb +24 -0
- data/lib/doto/migration/raw_helpers/color_theme_hash.rb +13 -0
- data/lib/doto/migration/raw_helpers/configuration_hash.rb +15 -0
- data/lib/doto/migration/raw_helpers/entry_group_hash.rb +13 -0
- data/lib/doto/migration/raw_json_file.rb +15 -0
- data/lib/doto/migration/raw_json_files.rb +56 -0
- data/lib/doto/migration/v20230613121411/service.rb +94 -0
- data/lib/doto/migration/v20240210161248/service.rb +148 -0
- data/lib/doto/migration/version.rb +7 -0
- data/lib/doto/models/color_theme.rb +224 -0
- data/lib/doto/models/configuration.rb +185 -0
- data/lib/doto/models/entry.rb +63 -0
- data/lib/doto/models/entry_group.rb +223 -0
- data/lib/doto/models/migration_version.rb +49 -0
- data/lib/doto/models/project.rb +295 -0
- data/lib/doto/presenters/base_presenter.rb +32 -0
- data/lib/doto/presenters/base_presenter_ex.rb +15 -0
- data/lib/doto/presenters/color_theme_presenter.rb +52 -0
- data/lib/doto/presenters/color_theme_show_presenter.rb +55 -0
- data/lib/doto/presenters/configuration_presenter.rb +50 -0
- data/lib/doto/presenters/entry_group/list/date_presenter.rb +77 -0
- data/lib/doto/presenters/entry_group/list/dates_presenter.rb +60 -0
- data/lib/doto/presenters/entry_group/list/messages.rb +15 -0
- data/lib/doto/presenters/entry_group/list/nothing_to_list.rb +15 -0
- data/lib/doto/presenters/entry_group_presenter.rb +35 -0
- data/lib/doto/presenters/entry_presenter.rb +25 -0
- data/lib/doto/presenters/export/all_presenter.rb +44 -0
- data/lib/doto/presenters/export/dates_presenter.rb +55 -0
- data/lib/doto/presenters/import/all_presenter.rb +57 -0
- data/lib/doto/presenters/import/dates_presenter.rb +70 -0
- data/lib/doto/presenters/import/import_entry.rb +22 -0
- data/lib/doto/presenters/import/import_file.rb +33 -0
- data/lib/doto/presenters/project/create_presenter.rb +44 -0
- data/lib/doto/presenters/project/defaultable.rb +15 -0
- data/lib/doto/presenters/project/delete_by_number_presenter.rb +54 -0
- data/lib/doto/presenters/project/delete_presenter.rb +53 -0
- data/lib/doto/presenters/project/list_presenter.rb +24 -0
- data/lib/doto/presenters/project/rename_by_number_presenter.rb +63 -0
- data/lib/doto/presenters/project/rename_presenter.rb +57 -0
- data/lib/doto/presenters/project/use_by_number_presenter.rb +57 -0
- data/lib/doto/presenters/project/use_presenter.rb +56 -0
- data/lib/doto/services/color_theme/hydrator_service.rb +42 -0
- data/lib/doto/services/configuration/hydrator_service.rb +42 -0
- data/lib/doto/services/entry/hydrator_service.rb +33 -0
- data/lib/doto/services/entry_group/browse_service.rb +100 -0
- data/lib/doto/services/entry_group/counter_service.rb +32 -0
- data/lib/doto/services/entry_group/deleter_service.rb +35 -0
- data/lib/doto/services/entry_group/editor_service.rb +103 -0
- data/lib/doto/services/entry_group/exporter_service.rb +98 -0
- data/lib/doto/services/entry_group/hydrator_service.rb +37 -0
- data/lib/doto/services/entry_group/importer_service.rb +117 -0
- data/lib/doto/services/migration_version/hydrator_service.rb +36 -0
- data/lib/doto/services/project/hydrator_service.rb +40 -0
- data/lib/doto/services/project/rename_service.rb +70 -0
- data/lib/doto/services/stderr_redirector_service.rb +27 -0
- data/lib/doto/services/stdout_redirector_service.rb +27 -0
- data/lib/doto/services/temp_file/reader_service.rb +33 -0
- data/lib/doto/services/temp_file/writer_service.rb +35 -0
- data/lib/doto/subcommands/base_subcommand.rb +12 -0
- data/lib/doto/subcommands/browse.rb +49 -0
- data/lib/doto/subcommands/config.rb +81 -0
- data/lib/doto/subcommands/delete.rb +108 -0
- data/lib/doto/subcommands/edit.rb +48 -0
- data/lib/doto/subcommands/export.rb +62 -0
- data/lib/doto/subcommands/import.rb +72 -0
- data/lib/doto/subcommands/list.rb +95 -0
- data/lib/doto/subcommands/project.rb +146 -0
- data/lib/doto/subcommands/theme.rb +131 -0
- data/lib/doto/support/ask.rb +44 -0
- data/lib/doto/support/color_themable.rb +36 -0
- data/lib/doto/support/command_help_colorizeable.rb +34 -0
- data/lib/doto/support/command_hookable.rb +71 -0
- data/lib/doto/support/command_options/doto_times.rb +48 -0
- data/lib/doto/support/command_options/time.rb +84 -0
- data/lib/doto/support/command_options/time_mnemonic.rb +108 -0
- data/lib/doto/support/command_options/time_mnemonics.rb +16 -0
- data/lib/doto/support/descriptable.rb +29 -0
- data/lib/doto/support/entry_group_browsable.rb +104 -0
- data/lib/doto/support/field_errors.rb +11 -0
- data/lib/doto/support/fileable.rb +136 -0
- data/lib/doto/support/presentable.rb +11 -0
- data/lib/doto/support/project_file_system.rb +118 -0
- data/lib/doto/support/short_string.rb +24 -0
- data/lib/doto/support/time_comparable.rb +21 -0
- data/lib/doto/support/time_formatable.rb +65 -0
- data/lib/doto/support/times_sortable.rb +71 -0
- data/lib/doto/support/transform_project_name.rb +24 -0
- data/lib/doto/support/utils.rb +11 -0
- data/lib/doto/validators/color_theme_validator.rb +74 -0
- data/lib/doto/validators/description_validator.rb +51 -0
- data/lib/doto/validators/entries_validator.rb +77 -0
- data/lib/doto/validators/project_name_validator.rb +58 -0
- data/lib/doto/validators/time_validator.rb +25 -0
- data/lib/doto/validators/version_validator.rb +29 -0
- data/lib/doto/version.rb +6 -0
- data/lib/doto/views/base_list_view.rb +41 -0
- data/lib/doto/views/color_theme/index.rb +62 -0
- data/lib/doto/views/color_theme/show.rb +107 -0
- data/lib/doto/views/configuration/show.rb +41 -0
- data/lib/doto/views/entry_group/edit.rb +121 -0
- data/lib/doto/views/entry_group/list.rb +23 -0
- data/lib/doto/views/entry_group/shared/no_entries_to_display.rb +53 -0
- data/lib/doto/views/entry_group/shared/no_entries_to_display_for_month_of.rb +32 -0
- data/lib/doto/views/entry_group/shared/no_entries_to_display_for_week_of.rb +33 -0
- data/lib/doto/views/entry_group/shared/no_entries_to_display_for_year_of.rb +33 -0
- data/lib/doto/views/entry_group/show.rb +63 -0
- data/lib/doto/views/export.rb +82 -0
- data/lib/doto/views/import.rb +105 -0
- data/lib/doto/views/import_dates.rb +17 -0
- data/lib/doto/views/project/create.rb +87 -0
- data/lib/doto/views/project/delete.rb +96 -0
- data/lib/doto/views/project/delete_by_number.rb +19 -0
- data/lib/doto/views/project/list.rb +115 -0
- data/lib/doto/views/project/rename.rb +98 -0
- data/lib/doto/views/project/rename_by_number.rb +21 -0
- data/lib/doto/views/project/use.rb +97 -0
- data/lib/doto/views/project/use_by_number.rb +19 -0
- data/lib/doto/views/shared/error.rb +17 -0
- data/lib/doto/views/shared/info.rb +17 -0
- data/lib/doto/views/shared/message.rb +85 -0
- data/lib/doto/views/shared/model_errors.rb +32 -0
- data/lib/doto/views/shared/success.rb +17 -0
- data/lib/doto/views/shared/warning.rb +17 -0
- data/lib/doto.rb +33 -0
- data/lib/locales/en/active_record.yml +17 -0
- data/lib/locales/en/commands.yml +165 -0
- data/lib/locales/en/miscellaneous.yml +29 -0
- data/lib/locales/en/presenters.yml +19 -0
- data/lib/locales/en/services.yml +14 -0
- data/lib/locales/en/subcommands.yml +786 -0
- data/lib/seed_data/0/.todo +5 -0
- data/lib/seed_data/20230613121411/.doto +8 -0
- data/lib/seed_data/20230613121411/doto/migration_version.json +3 -0
- data/lib/seed_data/20230613121411/doto/themes/cherry.json +79 -0
- data/lib/seed_data/20230613121411/doto/themes/christmas.json +79 -0
- data/lib/seed_data/20230613121411/doto/themes/default.json +79 -0
- data/lib/seed_data/20230613121411/doto/themes/lemon.json +79 -0
- data/lib/seed_data/20230613121411/doto/themes/light.json +79 -0
- data/lib/seed_data/20230613121411/doto/themes/matrix.json +79 -0
- data/lib/seed_data/20230613121411/doto/themes/whiteout.json +79 -0
- data/lib/seed_data/20240210161248/.doto +9 -0
- data/lib/seed_data/20240210161248/doto/current_project.json +4 -0
- data/lib/seed_data/20240210161248/doto/migration_version.json +3 -0
- data/lib/seed_data/20240210161248/doto/projects/default/project.json +5 -0
- data/lib/seed_data/20240210161248/doto/themes/cherry.json +79 -0
- data/lib/seed_data/20240210161248/doto/themes/christmas.json +79 -0
- data/lib/seed_data/20240210161248/doto/themes/default.json +79 -0
- data/lib/seed_data/20240210161248/doto/themes/lemon.json +79 -0
- data/lib/seed_data/20240210161248/doto/themes/light.json +79 -0
- data/lib/seed_data/20240210161248/doto/themes/matrix.json +79 -0
- data/lib/seed_data/20240210161248/doto/themes/whiteout.json +79 -0
- data/sig/dsu.rbs +4 -0
- 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,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
|