From 0d7e2a1a32ec19303c26d5e450f21695f2c2b1c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nick=20Fl=C3=BCckiger?= Date: Wed, 5 May 2021 17:20:07 +0200 Subject: [PATCH] Implement work report query builder (#21) --- app/controllers/time_tracker_controller.rb | 14 ++--- app/controllers/timer_sessions_controller.rb | 10 ++++ app/models/work_report_query.rb | 8 +++ app/services/work_report_query_builder.rb | 48 +++++++++++++-- .../_entries_report_query.html.slim | 7 ++- app/views/timer_sessions/index.html.slim | 2 +- config/routes.rb | 2 + test/unit/display_date_format_builder_test.rb | 6 +- test/unit/work_report_query_builder_test.rb | 59 +++++++++++++++++++ 9 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 app/models/work_report_query.rb create mode 100644 test/unit/work_report_query_builder_test.rb diff --git a/app/controllers/time_tracker_controller.rb b/app/controllers/time_tracker_controller.rb index 178d8f80..78f91bc9 100644 --- a/app/controllers/time_tracker_controller.rb +++ b/app/controllers/time_tracker_controller.rb @@ -8,13 +8,12 @@ def start if @current_timer_session respond_with_error(error: :timer_already_present) else - timer_session = SessionCreator.new(@current_user, timer_params).create - issue_connector = IssueConnector.new(timer_params[:issue_ids] || [], timer_session) + @timer_session = SessionCreator.new(@current_user, timer_params).create + issue_connector = IssueConnector.new(timer_params[:issue_ids] || [], @timer_session) issue_connector.run - if timer_session.session_finished? + if @timer_session.session_finished? handle_finished_timer_session else - @timer_session = timer_session render :start, layout: false end end @@ -36,13 +35,12 @@ def update private def handle_finished_timer_session - if timer_session.valid? - time_splitter = TimeSplitter.new(timer_session) + if @timer_session.valid? + time_splitter = TimeSplitter.new(@timer_session) time_splitter.create_time_entries - timer_session.update(finished: true) + @timer_session.update(finished: true) render :stop, layout: true else - @timer_session = timer_session render :start, layout: false end end diff --git a/app/controllers/timer_sessions_controller.rb b/app/controllers/timer_sessions_controller.rb index 77c85fd0..96c406fc 100644 --- a/app/controllers/timer_sessions_controller.rb +++ b/app/controllers/timer_sessions_controller.rb @@ -10,6 +10,12 @@ def index .group_by { |entry| entry.timer_start&.to_date } end + def report + work_report_query = WorkReportQuery.new(report_query_params) + result_url = WorkReportQueryBuilder.new(work_report_query).build_query + redirect_to result_url + end + def destroy timer_session = TimerSession.find(params[:id]) TimerEntityCleaner.new(timer_session).run @@ -33,4 +39,8 @@ def set_current_user def set_current_timer_session @current_timer_session = TimerSession.active_session(@current_user.id).first end + + def report_query_params + params.require(:work_report_query).permit(:date, :period) + end end diff --git a/app/models/work_report_query.rb b/app/models/work_report_query.rb new file mode 100644 index 00000000..c4f37093 --- /dev/null +++ b/app/models/work_report_query.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class WorkReportQuery + include ActiveModel::Model + extend ActiveModel::Naming + + attr_accessor :period, :date +end diff --git a/app/services/work_report_query_builder.rb b/app/services/work_report_query_builder.rb index 68c9d4a1..21edff00 100644 --- a/app/services/work_report_query_builder.rb +++ b/app/services/work_report_query_builder.rb @@ -1,12 +1,52 @@ # frozen_string_literal: true class WorkReportQueryBuilder + include Rails.application.routes.url_helpers + AVAILABLE_PERIODS = %i[day week month year].freeze + DATE_FORMAT_FOR_QUERY = '%Y-%m-%d' + COLUMNS_TO_QUERY = %w[project spent_on activity issue comments hours].freeze + BETWEEN_OPERATOR = '><' + FILTERS_TO_USE = ['spent_on', 'user_id', ''].freeze + QUERY_CURRENT_USER_SYMBOL = 'me' + FILTER_STATUS = '1' + + def initialize(work_report_query) + @work_report_query = work_report_query + @date = Date.parse(@work_report_query.date) + end - def initialize(date, period: :week) - @date = date - @period = period + def build_query + date_range = build_date_range.map { |date| date.strftime(DATE_FORMAT_FOR_QUERY) } + build_report_query(date_range) end - def build_report_query; end + private + + def build_report_query(date_range) + time_entries_path( + set_filter: FILTER_STATUS, sort: 'spent_on:desc', + f: FILTERS_TO_USE, + op: { spent_on: BETWEEN_OPERATOR, user_id: '=' }, + v: { spent_on: [date_range.first, date_range.last], user_id: [QUERY_CURRENT_USER_SYMBOL] }, + c: COLUMNS_TO_QUERY, group_by: '', t: ['hours'] + ) + end + + def valid? + AVAILABLE_PERIODS.include?(@work_report_query.period) + end + + def build_date_range + case @work_report_query.period.to_sym + when :day + [@date, @date] + when :week + [@date.beginning_of_week, @date.end_of_week] + when :month + [@date.beginning_of_month, @date.end_of_month] + when :year + [@date.beginning_of_year, @date.end_of_year] + end + end end diff --git a/app/views/timer_sessions/_entries_report_query.html.slim b/app/views/timer_sessions/_entries_report_query.html.slim index ce704d0b..4a521ea9 100644 --- a/app/views/timer_sessions/_entries_report_query.html.slim +++ b/app/views/timer_sessions/_entries_report_query.html.slim @@ -1,5 +1,8 @@ .box - = form_for :entry_report_query do |f| - = f.date_field :date + - current_report_query = current_report || WorkReportQuery.new + = labelled_form_for(current_report_query, url: timer_sessions_report_path, method: :get) do |f| + = f.date_field :date, value: Time.zone.now.to_date + br = f.select :period, %i[day week month year] + br = f.submit :see_query diff --git a/app/views/timer_sessions/index.html.slim b/app/views/timer_sessions/index.html.slim index b7291b6b..cf0d4251 100644 --- a/app/views/timer_sessions/index.html.slim +++ b/app/views/timer_sessions/index.html.slim @@ -5,7 +5,7 @@ = render 'timer_container', timer_session: @current_timer_session hr div[data-timer-session-container] - = render 'entries_report_query' + = render 'entries_report_query', current_report: @current_report hr div[data-timer-sessions-list] = render 'timer_sessions_list', timer_sessions_by_day: @timer_sessions diff --git a/config/routes.rb b/config/routes.rb index c150b97d..114cd993 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,6 +4,8 @@ # See: http://guides.rubyonrails.org/routing.htm resources :timer_sessions, only: %i[index edit update patch destroy] +get 'timer_sessions_report', to: 'timer_sessions#report', as: :timer_sessions_report + post 'time_tracker/start', to: 'time_tracker#start', as: :start_time_tracker post 'time_tracker/stop', to: 'time_tracker#stop', as: :stop_time_tracker post 'time_tracker/update', to: 'time_tracker#update', as: :update_time_tracker diff --git a/test/unit/display_date_format_builder_test.rb b/test/unit/display_date_format_builder_test.rb index 0357b90a..9ae55cf6 100644 --- a/test/unit/display_date_format_builder_test.rb +++ b/test/unit/display_date_format_builder_test.rb @@ -2,7 +2,7 @@ class DisplayDateFormatBuilderTest < ActiveSupport::TestCase - test 'format_for_same_date' do + test 'format for same date' do formatter = DisplayDateFormatBuilder.new( Time.zone.local(2001, 2, 3, 4, 5, 6), Time.zone.local(2001, 2, 3, 4, 5, 6) @@ -10,7 +10,7 @@ class DisplayDateFormatBuilderTest < ActiveSupport::TestCase assert_equal('04:05 - 04:05', formatter.format) end - test 'format_for_date_with_same_year' do + test 'format for date with same year' do formatter = DisplayDateFormatBuilder.new( Time.zone.local(2001, 10, 3, 4, 5, 6), Time.zone.local(2001, 2, 3, 4, 5, 6) @@ -18,7 +18,7 @@ class DisplayDateFormatBuilderTest < ActiveSupport::TestCase assert_equal('03.10 04:05 - 03.02 04:05', formatter.format) end - test 'format_with_different_year' do + test 'format with different year' do formatter = DisplayDateFormatBuilder.new( Time.zone.local(2001, 10, 3, 4, 5, 6), Time.zone.local(2002, 10, 3, 4, 5, 6) diff --git a/test/unit/work_report_query_builder_test.rb b/test/unit/work_report_query_builder_test.rb new file mode 100644 index 00000000..2917cc85 --- /dev/null +++ b/test/unit/work_report_query_builder_test.rb @@ -0,0 +1,59 @@ +require File.expand_path('../test_helper', __dir__) + +class WorkReportQueryBuilderTest < ActiveSupport::TestCase + test 'build query for day report' do + work_report_query = WorkReportQuery.new( + date: Date.new(2021, 10, 30).to_s, + period: :day + ) + expected_query = URI.decode("/time_entries?c%5B%5D=project&c%5B%5D=spent_on"+ + "&c%5B%5D=activity&c%5B%5D=issue&c%5B%5D=comments"+ + "&c%5B%5D=hours&f%5B%5D=spent_on&f%5B%5D=user_id"+ + "&f%5B%5D=&group_by=&op%5Bspent_on%5D=%3E%3C&op%5Buser_id"+ + "%5D=%3D&set_filter=1&sort=spent_on%3Adesc&t%5B%5D=hours&v%5Bspent_on"+ + "%5D%5B%5D=2021-10-30&v%5Bspent_on%5D%5B%5D=2021-10-30&v%5Buser_id%5D%5B%5D=me") + assert_equal expected_query, URI.decode(WorkReportQueryBuilder.new(work_report_query).build_query) + end + + test 'build query for week report' do + work_report_query = WorkReportQuery.new( + date: Date.new(2021, 10, 30).to_s, + period: :week + ) + expected_query = URI.decode("/time_entries?c%5B%5D=project&c%5B%5D=spent_on"+ + "&c%5B%5D=activity&c%5B%5D=issue&c%5B%5D=comments"+ + "&c%5B%5D=hours&f%5B%5D=spent_on&f%5B%5D=user_id"+ + "&f%5B%5D=&group_by=&op%5Bspent_on%5D=%3E%3C&op%5Buser_id"+ + "%5D=%3D&set_filter=1&sort=spent_on%3Adesc&t%5B%5D=hours&v%5Bspent_on"+ + "%5D%5B%5D=2021-10-25&v%5Bspent_on%5D%5B%5D=2021-10-31&v%5Buser_id%5D%5B%5D=me") + assert_equal expected_query, URI.decode(WorkReportQueryBuilder.new(work_report_query).build_query) + end + + test 'build query for month report' do + work_report_query = WorkReportQuery.new( + date: Date.new(2021, 10, 30).to_s, + period: :month + ) + expected_query = URI.decode("/time_entries?c%5B%5D=project&c%5B%5D=spent_on"+ + "&c%5B%5D=activity&c%5B%5D=issue&c%5B%5D=comments"+ + "&c%5B%5D=hours&f%5B%5D=spent_on&f%5B%5D=user_id"+ + "&f%5B%5D=&group_by=&op%5Bspent_on%5D=%3E%3C&op%5Buser_id"+ + "%5D=%3D&set_filter=1&sort=spent_on%3Adesc&t%5B%5D=hours&v%5Bspent_on"+ + "%5D%5B%5D=2021-10-01&v%5Bspent_on%5D%5B%5D=2021-10-31&v%5Buser_id%5D%5B%5D=me") + assert_equal expected_query, URI.decode(WorkReportQueryBuilder.new(work_report_query).build_query) + end + + test 'build query for year report' do + work_report_query = WorkReportQuery.new( + date: Date.new(2021, 10, 30).to_s, + period: :year + ) + expected_query = URI.decode("/time_entries?c%5B%5D=project&c%5B%5D=spent_on"+ + "&c%5B%5D=activity&c%5B%5D=issue&c%5B%5D=comments"+ + "&c%5B%5D=hours&f%5B%5D=spent_on&f%5B%5D=user_id"+ + "&f%5B%5D=&group_by=&op%5Bspent_on%5D=%3E%3C&op%5Buser_id"+ + "%5D=%3D&set_filter=1&sort=spent_on%3Adesc&t%5B%5D=hours&v%5Bspent_on"+ + "%5D%5B%5D=2021-01-01&v%5Bspent_on%5D%5B%5D=2021-12-31&v%5Buser_id%5D%5B%5D=me") + assert_equal expected_query, URI.decode(WorkReportQueryBuilder.new(work_report_query).build_query) + end +end