mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
Merge pull request #16567 from opf/bug/56771-meeting-timestamp-in-edit-form-not-the-same-as-in-details
Bug/56771 meeting timestamp in edit form not the same as in details
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
|
||||
module Settings
|
||||
##
|
||||
# A text field to enter numeric values.
|
||||
# A select field to select a time zone from.
|
||||
class TimeZoneSettingComponent < ::ApplicationComponent
|
||||
options :form, :title
|
||||
options container_class: "-wide"
|
||||
|
||||
@@ -27,31 +27,25 @@
|
||||
#++
|
||||
|
||||
class AnonymousUser < User
|
||||
validate :validate_unique_anonymous_user, on: :create
|
||||
|
||||
# There should be only one AnonymousUser in the database
|
||||
def validate_unique_anonymous_user
|
||||
errors.add :base, "An anonymous user already exists." if AnonymousUser.any?
|
||||
end
|
||||
|
||||
def available_custom_fields
|
||||
[]
|
||||
end
|
||||
|
||||
# Overrides a few properties
|
||||
def logged?; false end
|
||||
|
||||
def builtin?; true end
|
||||
|
||||
def admin; false end
|
||||
include Users::FunctionUser
|
||||
|
||||
def name(*_args); I18n.t(:label_user_anonymous) end
|
||||
|
||||
def mail; nil end
|
||||
def self.first
|
||||
anonymous_user = super
|
||||
|
||||
def time_zone; nil end
|
||||
if anonymous_user.nil?
|
||||
(anonymous_user = new.tap do |u|
|
||||
u.lastname = "Anonymous"
|
||||
u.login = ""
|
||||
u.firstname = ""
|
||||
u.mail = ""
|
||||
u.status = User.statuses[:active]
|
||||
end).save
|
||||
|
||||
def rss_key; nil end
|
||||
raise "Unable to create the anonymous user." if anonymous_user.new_record?
|
||||
end
|
||||
|
||||
def destroy; false end
|
||||
anonymous_user
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,23 +1,9 @@
|
||||
class DeletedUser < User
|
||||
validate :validate_unique_deleted_user, on: :create
|
||||
|
||||
# There should be only one DeletedUser in the database
|
||||
def validate_unique_deleted_user
|
||||
errors.add :base, "A DeletedUser already exists." if DeletedUser.any?
|
||||
end
|
||||
|
||||
def self.first
|
||||
super || create(type: to_s, status: statuses[:locked])
|
||||
end
|
||||
|
||||
# Overrides a few properties
|
||||
def available_custom_fields = []
|
||||
def logged? = false
|
||||
def builtin? = true
|
||||
def admin = false
|
||||
include Users::FunctionUser
|
||||
|
||||
def name(*_args) = I18n.t("user.deleted")
|
||||
def mail = nil
|
||||
def time_zone = nil
|
||||
def rss_key = nil
|
||||
def destroy = false
|
||||
end
|
||||
|
||||
@@ -84,7 +84,7 @@ module Exports
|
||||
def csv_export_filename
|
||||
sane_filename(
|
||||
"#{Setting.app_title} #{title} \
|
||||
#{format_time_as_date(Time.zone.now, '%Y-%m-%d')}.csv"
|
||||
#{format_time_as_date(Time.zone.now, format: '%Y-%m-%d')}.csv"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
+23
-19
@@ -31,31 +31,35 @@
|
||||
#
|
||||
|
||||
class SystemUser < User
|
||||
validate :validate_unique_system_user, on: :create
|
||||
|
||||
# There should be only one SystemUser in the database
|
||||
def validate_unique_system_user
|
||||
errors.add :base, "A SystemUser already exists." if SystemUser.any?
|
||||
end
|
||||
|
||||
# Overrides a few properties
|
||||
def logged?; false end
|
||||
|
||||
def builtin?; true end
|
||||
include Users::FunctionUser
|
||||
|
||||
def name(*_args); "System" end
|
||||
|
||||
def mail; nil end
|
||||
|
||||
def time_zone; nil end
|
||||
|
||||
def rss_key; nil end
|
||||
|
||||
def destroy; false end
|
||||
|
||||
def run_given
|
||||
User.execute_as(self) do
|
||||
yield self
|
||||
end
|
||||
end
|
||||
|
||||
def self.first
|
||||
system_user = super
|
||||
|
||||
if system_user.nil?
|
||||
system_user = new(
|
||||
firstname: "",
|
||||
lastname: "System",
|
||||
login: "",
|
||||
mail: "",
|
||||
admin: true,
|
||||
status: User.statuses[:active],
|
||||
first_login: false
|
||||
)
|
||||
|
||||
system_user.save
|
||||
|
||||
raise "Unable to create the system user." unless system_user.persisted?
|
||||
end
|
||||
|
||||
system_user
|
||||
end
|
||||
end
|
||||
|
||||
+12
-40
@@ -399,7 +399,7 @@ class User < Principal
|
||||
end
|
||||
|
||||
def log_successful_login
|
||||
update_attribute(:last_login_on, Time.now)
|
||||
update_attribute(:last_login_on, Time.current)
|
||||
end
|
||||
|
||||
def pref
|
||||
@@ -407,7 +407,13 @@ class User < Principal
|
||||
end
|
||||
|
||||
def time_zone
|
||||
@time_zone ||= (pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[pref.time_zone])
|
||||
@time_zone ||= ActiveSupport::TimeZone[pref.time_zone] || ActiveSupport::TimeZone["Etc/UTC"]
|
||||
end
|
||||
|
||||
def reload(*)
|
||||
@time_zone = nil
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def wants_comments_in_reverse_order?
|
||||
@@ -538,46 +544,12 @@ class User < Principal
|
||||
|
||||
# Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
|
||||
# one anonymous user per database.
|
||||
def self.anonymous # rubocop:disable Metrics/AbcSize
|
||||
RequestStore[:anonymous_user] ||=
|
||||
begin
|
||||
anonymous_user = AnonymousUser.first
|
||||
|
||||
if anonymous_user.nil?
|
||||
(anonymous_user = AnonymousUser.new.tap do |u|
|
||||
u.lastname = "Anonymous"
|
||||
u.login = ""
|
||||
u.firstname = ""
|
||||
u.mail = ""
|
||||
u.status = User.statuses[:active]
|
||||
end).save
|
||||
|
||||
raise "Unable to create the anonymous user." if anonymous_user.new_record?
|
||||
end
|
||||
anonymous_user
|
||||
end
|
||||
def self.anonymous
|
||||
RequestStore[:anonymous_user] ||= AnonymousUser.first
|
||||
end
|
||||
|
||||
def self.system
|
||||
system_user = SystemUser.first
|
||||
|
||||
if system_user.nil?
|
||||
system_user = SystemUser.new(
|
||||
firstname: "",
|
||||
lastname: "System",
|
||||
login: "",
|
||||
mail: "",
|
||||
admin: true,
|
||||
status: User.statuses[:active],
|
||||
first_login: false
|
||||
)
|
||||
|
||||
system_user.save(validate: false)
|
||||
|
||||
raise "Unable to create the automatic migration user." unless system_user.persisted?
|
||||
end
|
||||
|
||||
system_user
|
||||
SystemUser.first
|
||||
end
|
||||
|
||||
protected
|
||||
@@ -689,6 +661,6 @@ class User < Principal
|
||||
end
|
||||
|
||||
def self.default_admin_account_changed?
|
||||
!User.active.find_by_login("admin").try(:current_password).try(:matches_plaintext?, "admin") # rubocop:disable Rails/DynamicFindBy
|
||||
!User.active.find_by_login("admin").try(:current_password).try(:matches_plaintext?, "admin")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -132,7 +132,11 @@ class UserPreference < ApplicationRecord
|
||||
end
|
||||
|
||||
def time_zone
|
||||
super.presence || Setting.user_default_timezone.presence
|
||||
super.presence || Setting.user_default_timezone.presence || "Etc/UTC"
|
||||
end
|
||||
|
||||
def time_zone?
|
||||
settings["time_zone"].present?
|
||||
end
|
||||
|
||||
def daily_reminders
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Users::FunctionUser
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
validate :validate_unique_function_user, on: :create
|
||||
|
||||
# There should be only one such user in the database
|
||||
def validate_unique_function_user
|
||||
errors.add :base, "A #{self.class.name} already exists." if self.class.any?
|
||||
end
|
||||
|
||||
def available_custom_fields = []
|
||||
|
||||
def logged? = false
|
||||
|
||||
def builtin? = true
|
||||
|
||||
def name(*_args); raise NotImplementedError end
|
||||
|
||||
def mail = nil
|
||||
|
||||
def time_zone; ActiveSupport::TimeZone[Setting.user_default_timezone.presence || "Etc/UTC"] end
|
||||
|
||||
def rss_key = nil
|
||||
|
||||
def destroy = false
|
||||
end
|
||||
end
|
||||
@@ -127,7 +127,7 @@ module WorkPackage::PDFExport::Page
|
||||
end
|
||||
|
||||
def footer_date
|
||||
format_time(Time.zone.now, true)
|
||||
format_time(Time.zone.now)
|
||||
end
|
||||
|
||||
def total_page_nr_text
|
||||
|
||||
@@ -48,7 +48,6 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
<%= render Settings::TimeZoneSettingComponent.new(
|
||||
"user_default_timezone",
|
||||
container_class: "-slim",
|
||||
title: I18n.t("tooltip_user_default_timezone")
|
||||
)
|
||||
%>
|
||||
|
||||
@@ -30,6 +30,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<%= render Settings::TimeZoneSettingComponent.new(
|
||||
"time_zone",
|
||||
form: pref_fields,
|
||||
include_blank: false,
|
||||
container_class: (defined? input_size) ? "-#{input_size}" : "-wide"
|
||||
)
|
||||
%>
|
||||
|
||||
+33
-17
@@ -115,18 +115,18 @@ module Redmine
|
||||
/(\[(.+?)\]\((.+?)\))/
|
||||
end
|
||||
|
||||
# Format the time to a date in the user time zone if one is set.
|
||||
# If none is set and the time is in utc time zone (meaning it came from active record), format the date in the system timezone
|
||||
# otherwise just use the date in the time zone attached to the time.
|
||||
def format_time_as_date(time, format = nil)
|
||||
# Formats the given time as a date string according to the user's time zone and
|
||||
# optional specified format.
|
||||
#
|
||||
# @param time [Time] The time to format.
|
||||
# @param format [String, nil] The strftime format to use for the date. If nil, the default
|
||||
# date format from `Setting.date_format` is used.
|
||||
# @return [String, nil] The formatted date string, or nil if the time is not provided.
|
||||
def format_time_as_date(time, format: nil)
|
||||
return nil unless time
|
||||
|
||||
zone = User.current.time_zone
|
||||
local_date = (if zone
|
||||
time.in_time_zone(zone)
|
||||
else
|
||||
time.utc? ? time.localtime : time
|
||||
end).to_date
|
||||
local_date = time.in_time_zone(zone).to_date
|
||||
|
||||
if format
|
||||
local_date.strftime(format)
|
||||
@@ -135,18 +135,34 @@ module Redmine
|
||||
end
|
||||
end
|
||||
|
||||
def format_time(time, include_date = true)
|
||||
# Formats the given time as a time string according to the user's time zone
|
||||
# and optional specified format.
|
||||
#
|
||||
# @param time [Time] The time to format.
|
||||
# @param include_date [Boolean] Whether to include the date in the formatted
|
||||
# output. Defaults to true.
|
||||
# @param format [String] The strftime format to use for the time. Defaults
|
||||
# to the format in `Setting.time_format`.
|
||||
# @return [String, nil] The formatted time string, or nil if the time is not
|
||||
# provided.
|
||||
def format_time(time, include_date: true, format: Setting.time_format)
|
||||
return nil unless time
|
||||
|
||||
time = time.to_time if time.is_a?(String)
|
||||
zone = User.current.time_zone
|
||||
local = if zone
|
||||
time.in_time_zone(zone)
|
||||
else
|
||||
(time.utc? ? time.to_time.localtime : time)
|
||||
end
|
||||
local = time.in_time_zone(zone)
|
||||
|
||||
(include_date ? "#{format_date(local)} " : "") +
|
||||
(Setting.time_format.blank? ? ::I18n.l(local, format: :time) : local.strftime(Setting.time_format))
|
||||
(format.blank? ? ::I18n.l(local, format: :time) : local.strftime(format))
|
||||
end
|
||||
|
||||
# Returns the offset to UTC (with utc prepended) currently active
|
||||
# in the current users time zone. DST is factored in so the offset can
|
||||
# shift over the course of the year
|
||||
def formatted_time_zone_offset
|
||||
# Doing User.current.time_zone and format that will not take heed of DST as it has no notion
|
||||
# of a current time.
|
||||
# https://github.com/rails/rails/issues/7297
|
||||
"UTC#{User.current.time_zone.now.formatted_offset}"
|
||||
end
|
||||
|
||||
def day_name(day)
|
||||
|
||||
@@ -43,7 +43,7 @@ module OpenProject::Bim::BcfXml
|
||||
|
||||
sane_filename(
|
||||
"#{Setting.app_title} #{I18n.t(:label_work_package_plural)} \
|
||||
#{format_time_as_date(Time.now, '%Y-%m-%d')}.bcf"
|
||||
#{format_time_as_date(Time.current, format: '%Y-%m-%d')}.bcf"
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ module Boards
|
||||
end
|
||||
|
||||
def created_at
|
||||
safe_join([helpers.format_date(model.created_at), helpers.format_time(model.created_at, false)], " ")
|
||||
safe_join([helpers.format_date(model.created_at), helpers.format_time(model.created_at, include_date: false)], " ")
|
||||
end
|
||||
|
||||
def type
|
||||
|
||||
@@ -47,7 +47,7 @@ module Meetings
|
||||
end
|
||||
|
||||
def start_time
|
||||
safe_join([helpers.format_date(model.start_time), helpers.format_time(model.start_time, false)], " ")
|
||||
safe_join([helpers.format_date(model.start_time), helpers.format_time(model.start_time, include_date: false)], " ")
|
||||
end
|
||||
|
||||
def duration
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
flex_layout(align_items: :center) do |time|
|
||||
time.with_column do
|
||||
render(Primer::Beta::Text.new) do
|
||||
"#{format_time(@meeting.start_time, false)} - #{format_time(@meeting.end_time, false)}"
|
||||
"#{format_time(@meeting.start_time, include_date: false)} - #{format_time(@meeting.end_time, include_date:false)}"
|
||||
end
|
||||
end
|
||||
|
||||
time.with_column(ml: 2) do
|
||||
render(Primer::Beta::Text.new(color: :subtle, font_size: :small)) do
|
||||
(User.current.time_zone || Time.zone).to_s[/\((.*?)\)/m, 1]
|
||||
formatted_time_zone_offset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,11 +45,11 @@ module Meetings
|
||||
private
|
||||
|
||||
def start_date_initial_value
|
||||
@meeting.start_time&.strftime("%Y-%m-%d")
|
||||
format_time_as_date(@meeting.start_time, format: "%Y-%m-%d")
|
||||
end
|
||||
|
||||
def start_time_initial_value
|
||||
@meeting.start_time&.strftime("%H:%M")
|
||||
format_time(@meeting.start_time, include_date: false, format: "%H:%M")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#++
|
||||
|
||||
class MeetingsController < ApplicationController
|
||||
around_action :set_time_zone
|
||||
before_action :load_and_authorize_in_optional_project, only: %i[index new show create history]
|
||||
before_action :verify_activities_module_activated, only: %i[history]
|
||||
before_action :determine_date_range, only: %i[history]
|
||||
@@ -96,8 +95,8 @@ class MeetingsController < ApplicationController
|
||||
|
||||
if call.success?
|
||||
text = I18n.t(:notice_successful_create)
|
||||
if User.current.time_zone.nil?
|
||||
link = I18n.t(:notice_timezone_missing, zone: Time.zone)
|
||||
unless User.current.pref.time_zone?
|
||||
link = I18n.t(:notice_timezone_missing, zone: formatted_time_zone_offset)
|
||||
text += " #{view_context.link_to(link, { controller: '/my', action: :settings, anchor: 'pref_time_zone' },
|
||||
class: 'link_to_profile')}"
|
||||
end
|
||||
@@ -288,17 +287,6 @@ class MeetingsController < ApplicationController
|
||||
.paginate(page: page_param, per_page: per_page_param)
|
||||
end
|
||||
|
||||
def set_time_zone(&)
|
||||
zone = User.current.time_zone
|
||||
if zone.nil?
|
||||
localzone = Time.current.utc_offset
|
||||
localzone -= 3600 if Time.current.dst?
|
||||
zone = ::ActiveSupport::TimeZone[localzone]
|
||||
end
|
||||
|
||||
Time.use_zone(zone, &)
|
||||
end
|
||||
|
||||
def build_meeting
|
||||
@meeting = Meeting.new
|
||||
@meeting.project = @project
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#++
|
||||
|
||||
class Meeting::StartTime < ApplicationForm
|
||||
include Redmine::I18n
|
||||
|
||||
form do |meeting_form|
|
||||
meeting_form.text_field(
|
||||
name: :start_time_hour,
|
||||
@@ -36,7 +38,7 @@ class Meeting::StartTime < ApplicationForm
|
||||
label: Meeting.human_attribute_name(:start_time),
|
||||
leading_visual: { icon: :clock },
|
||||
required: true,
|
||||
caption: Time.zone.to_s[/\((.*?)\)/m, 1]
|
||||
caption: formatted_time_zone_offset
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class MeetingAgendaItem::MeetingForm < ApplicationForm
|
||||
label: "#{meeting.project.name}: " \
|
||||
"#{meeting.title} " \
|
||||
"#{format_date(meeting.start_time)} " \
|
||||
"#{format_time(meeting.start_time, false)}",
|
||||
"#{format_time(meeting.start_time, include_date: false)}",
|
||||
value: meeting.id
|
||||
)
|
||||
end
|
||||
|
||||
@@ -63,8 +63,6 @@ class MeetingMailer < UserMailer
|
||||
set_headers @meeting
|
||||
|
||||
with_attached_ics(meeting, user) do
|
||||
timezone = Time.zone || Time.zone_default
|
||||
@formatted_timezone = format_timezone_offset timezone, @meeting.start_time
|
||||
subject = "[#{@meeting.project.name}] #{@meeting.title}"
|
||||
mail(to: user, subject:)
|
||||
end
|
||||
@@ -95,9 +93,4 @@ class MeetingMailer < UserMailer
|
||||
headers["Content-Type"] = 'text/calendar; charset=utf-8; method="PUBLISH"; name="meeting.ics"'
|
||||
headers["Content-Transfer-Encoding"] = "8bit"
|
||||
end
|
||||
|
||||
def format_timezone_offset(timezone, time)
|
||||
offset = ::ActiveSupport::TimeZone.seconds_to_utc_offset time.utc_offest_for_timezone(timezone), true
|
||||
"(GMT#{offset}) #{timezone.name}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -109,8 +109,8 @@ class Activities::MeetingActivityProvider < Activities::BaseActivityProvider
|
||||
end_time = start_time + event["meeting_duration"].to_f.hours
|
||||
|
||||
fstart_with = format_date start_time
|
||||
fstart_without = format_time start_time, false
|
||||
fend_without = format_time end_time, false
|
||||
fstart_without = format_time start_time, include_date: false
|
||||
fend_without = format_time end_time, include_date: false
|
||||
|
||||
"#{I18n.t(:label_meeting)}: #{event['meeting_title']} (#{fstart_with} #{fstart_without}-#{fend_without})"
|
||||
else
|
||||
|
||||
@@ -204,8 +204,8 @@ class Activities::MeetingEventMapper < Activities::EventMapper
|
||||
end_time = start_time + data[:meeting_duration].to_f.hours
|
||||
|
||||
fstart_with = format_date start_time
|
||||
fstart_without = format_time start_time, false
|
||||
fend_without = format_time end_time, false
|
||||
fstart_without = format_time start_time, include_date: false
|
||||
fend_without = format_time end_time, include_date: false
|
||||
|
||||
"#{I18n.t(:label_meeting)}: #{data[:meeting_title]} (#{fstart_with} #{fstart_without}-#{fend_without})"
|
||||
end
|
||||
|
||||
@@ -253,14 +253,15 @@ class Meeting < ApplicationRecord
|
||||
|
||||
def set_initial_values
|
||||
# set defaults
|
||||
write_attribute(:start_time, Date.tomorrow + 10.hours) if start_time.nil?
|
||||
# Start date is set to tomorrow at 10 AM (Current users local time)
|
||||
write_attribute(:start_time, User.current.time_zone.now.at_midnight + 34.hours) if start_time.nil?
|
||||
self.duration ||= 1
|
||||
update_derived_fields
|
||||
end
|
||||
|
||||
def update_derived_fields
|
||||
@start_date = start_time.to_date.iso8601
|
||||
@start_time_hour = start_time.strftime("%H:%M")
|
||||
@start_date = format_time_as_date(start_time, format: "%Y-%m-%d")
|
||||
@start_time_hour = format_time(start_time, include_date: false, format: "%H:%M")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -35,7 +35,7 @@ module Meeting::Journalized
|
||||
acts_as_event title: Proc.new { |o|
|
||||
"#{I18n.t(:label_meeting)}: #{o.title} \
|
||||
#{format_date o.start_time} \
|
||||
#{format_time o.start_time, false}-#{format_time o.end_time, false})"
|
||||
#{format_time o.start_time, include_date: false}-#{format_time o.end_time, include_date: false})"
|
||||
},
|
||||
url: Proc.new { |o| { controller: "/meetings", action: "show", id: o } },
|
||||
author: Proc.new(&:user),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<p><%= t(:text_notificiation_invited) %></p>
|
||||
|
||||
<ul>
|
||||
<li><%=t :label_meeting_date_time %>: <%= format_time_as_date @meeting.start_time %> <%= format_time @meeting.start_time, false %>-<%= format_time @meeting.end_time, false %> <%= @formatted_timezone %></li>
|
||||
<li><%=t :label_meeting_date_time %>: <%= format_time_as_date @meeting.start_time %> <%= format_time @meeting.start_time, include_date: false %>-<%= format_time @meeting.end_time, include_date: false %> (<%= formatted_time_zone_offset %>)</li>
|
||||
<li><%=Meeting.human_attribute_name(:location) %>: <%= @meeting.location %></li>
|
||||
<li><%=Meeting.human_attribute_name(:participants_invited) %>: <%= @meeting.participants.invited.sort.join("; ") %></li>
|
||||
<li><%=Meeting.human_attribute_name(:participants_attended) %>: <%= @meeting.participants.attended.sort.join("; ") %></li>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<%= t(:text_notificiation_invited) %>
|
||||
|
||||
<%=t :label_meeting_date_time %>: <%= format_time_as_date @meeting.start_time %> <%= format_time @meeting.start_time, false %>-<%= format_time @meeting.end_time, false %> <%= @formatted_timezone %>
|
||||
<%=t :label_meeting_date_time %>: <%= format_time_as_date @meeting.start_time %> <%= format_time @meeting.start_time, include_date: false %>-<%= format_time @meeting.end_time, include_date: false %> (<%= formatted_time_zone_offset %>)
|
||||
<%=Meeting.human_attribute_name(:location) %>: <%= @meeting.location %>
|
||||
<%=Meeting.human_attribute_name(:participants_invited) %>: <%= @meeting.participants.invited.sort.join("; ") %>
|
||||
<%=Meeting.human_attribute_name(:participants_attended) %>: <%= @meeting.participants.attended.sort.join("; ") %>
|
||||
|
||||
@@ -45,9 +45,9 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<%= I18n.t(:label_meeting_date_time) %>
|
||||
</td>
|
||||
<td style="<%= placeholder_text_styles %>">
|
||||
<%= format_time_as_date @meeting.start_time %> <%= format_time @meeting.start_time, false %>
|
||||
<%= format_time_as_date @meeting.start_time %> <%= format_time @meeting.start_time, include_date: false %>
|
||||
-
|
||||
<%= format_time @meeting.end_time, false %> <%= Time.zone %>
|
||||
<%= format_time @meeting.end_time, include_date: false %> (<%= formatted_time_zone_offset %>)
|
||||
</td>
|
||||
</tr>
|
||||
<% if @meeting.location.present? %>
|
||||
|
||||
@@ -32,7 +32,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<%= @meeting.project.name %>: <%= @meeting.title %> (<%= meeting_url(@meeting) %>)
|
||||
<%= @meeting.author %>
|
||||
|
||||
<%=t :label_meeting_date_time %>: <%= format_time_as_date @meeting.start_time %> <%= format_time @meeting.start_time, false %>-<%= format_time @meeting.end_time, false %> <%= Time.zone %>
|
||||
<%=t :label_meeting_date_time %>: <%= format_time_as_date @meeting.start_time %> <%= format_time @meeting.start_time, include_date: false %>-<%= format_time @meeting.end_time, include_date: false %> (<%= formatted_time_zone_offset %>)
|
||||
<%= Meeting.human_attribute_name(:location) %>: <%= @meeting.location %>
|
||||
<%= Meeting.human_attribute_name(:participants_invited) %>: <%= @meeting.participants.invited.sort.join("; ") %>
|
||||
<%= Meeting.human_attribute_name(:participants_attended) %>: <%= @meeting.participants.attended.sort.join("; ") %>
|
||||
|
||||
@@ -46,9 +46,9 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
</td>
|
||||
<td style="<%= placeholder_text_styles %>">
|
||||
<s>
|
||||
<%= format_time_as_date @changes[:old_start] %> <%= format_time @changes[:old_start], false %>
|
||||
<%= format_time_as_date @changes[:old_start] %> <%= format_time @changes[:old_start], include_date: false %>
|
||||
-
|
||||
<%= format_time (@changes[:old_start] + @changes[:old_duration].hours), false %> <%= Time.zone %>
|
||||
<%= format_time (@changes[:old_start] + @changes[:old_duration].hours), include_date: false %> (<%= formatted_time_zone_offset %>)
|
||||
</s>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -57,9 +57,9 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<%= t('meeting.email.rescheduled.new_date_time') %>
|
||||
</td>
|
||||
<td style="<%= placeholder_text_styles('font-weight': 'bold') %>">
|
||||
<%= format_time_as_date @changes[:new_start] %> <%= format_time @changes[:new_start], false %>
|
||||
<%= format_time_as_date @changes[:new_start] %> <%= format_time @changes[:new_start], include_date: false %>
|
||||
-
|
||||
<%= format_time (@changes[:new_start] + @changes[:new_duration].hours), false %> <%= Time.zone %>
|
||||
<%= format_time (@changes[:new_start] + @changes[:new_duration].hours), include_date: false %> (<%= formatted_time_zone_offset %>)
|
||||
</td>
|
||||
</tr>
|
||||
<% if @meeting.location.present? %>
|
||||
|
||||
@@ -35,7 +35,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
title: @meeting.title) %>
|
||||
|
||||
<%= t('meeting.email.rescheduled.old_date_time') %>:
|
||||
<%= format_time_as_date @changes[:old_start] %> <%= format_time @changes[:old_start], false %> - <%= format_time (@changes[:old_start] + @changes[:old_duration]), false %> <%= Time.zone %>
|
||||
<%= format_time_as_date @changes[:old_start] %> <%= format_time @changes[:old_start], include_date: false %> - <%= format_time (@changes[:old_start] + @changes[:old_duration]), include_date: false %> (<%= formatted_time_zone_offset %>}
|
||||
|
||||
<%= t('meeting.email.rescheduled.new_date_time') %>:
|
||||
<%= format_time_as_date @changes[:new_start] %> <%= format_time @changes[:new_start], false %> - <%= format_time (@changes[:new_start] + @changes[:new_duration]), false %> <%= Time.zone %>
|
||||
<%= format_time_as_date @changes[:new_start] %> <%= format_time @changes[:new_start], include_date: false %> - <%= format_time (@changes[:new_start] + @changes[:new_duration]), include_date: false %> (<%= formatted_time_zone_offset %>}
|
||||
|
||||
@@ -160,7 +160,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<%= Meeting.human_attribute_name(:start_time) %>
|
||||
<label lang="en">
|
||||
<%= t(:label_time_zone) %>
|
||||
<%= Time.zone.to_s %>
|
||||
<%= formatted_time_zone_offset %>
|
||||
</label>
|
||||
</label>
|
||||
<%= f.text_field :start_time_hour,
|
||||
@@ -169,7 +169,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
type: 'time',
|
||||
no_label: true,
|
||||
step: 5.minutes,
|
||||
suffix: Time.zone.to_s,
|
||||
suffix: formatted_time_zone_offset,
|
||||
container_class: '-xslim' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -100,8 +100,8 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
</div>
|
||||
<div class="grid-content small-6">
|
||||
<p>
|
||||
<strong><%= Meeting.human_attribute_name(:start_time) %></strong>: <%= format_date @meeting.start_time %> <%= format_time @meeting.start_time, false %>
|
||||
- <%= format_time @meeting.end_time, false %> <%= Time.zone %></p>
|
||||
<strong><%= Meeting.human_attribute_name(:start_time) %></strong>: <%= format_date @meeting.start_time %> <%= format_time @meeting.start_time, include_date: false %>
|
||||
- <%= format_time @meeting.end_time, include_date: false %> <%= formatted_time_zone_offset %></p>
|
||||
</div>
|
||||
<div class="grid-content small-6">
|
||||
<p>
|
||||
|
||||
@@ -34,7 +34,7 @@ RSpec.describe "Meetings copy", :js, :with_cuprite do
|
||||
shared_let(:user) do
|
||||
create(:user,
|
||||
member_with_permissions: { project => permissions }).tap do |u|
|
||||
u.pref[:time_zone] = "UTC"
|
||||
u.pref[:time_zone] = "Etc/UTC"
|
||||
|
||||
u.save!
|
||||
end
|
||||
@@ -66,7 +66,7 @@ RSpec.describe "Meetings copy", :js, :with_cuprite do
|
||||
start_of_meeting = start_time.strftime(twelve_hour_format)
|
||||
end_of_meeting = (start_time + meeting.duration.hours).strftime(twelve_hour_format)
|
||||
|
||||
"Start time: #{date} #{start_of_meeting} - #{end_of_meeting} (GMT+00:00) UTC"
|
||||
"Start time: #{date} #{start_of_meeting} - #{end_of_meeting} UTC+00:00"
|
||||
end
|
||||
|
||||
before do
|
||||
|
||||
@@ -33,7 +33,7 @@ require_relative "../support/pages/meetings/index"
|
||||
RSpec.describe "Meetings new", :js, with_cuprite: false do
|
||||
shared_let(:project) { create(:project, enabled_module_names: %w[meetings]) }
|
||||
shared_let(:admin) { create(:admin) }
|
||||
let(:time_zone) { "utc" }
|
||||
let(:time_zone) { "Etc/UTC" }
|
||||
let(:user) do
|
||||
create(:user,
|
||||
lastname: "First",
|
||||
|
||||
@@ -41,7 +41,7 @@ RSpec.describe "Structured meetings CRUD",
|
||||
lastname: "First",
|
||||
member_with_permissions: { project => %i[view_meetings create_meetings edit_meetings delete_meetings manage_agendas
|
||||
close_meeting_agendas view_work_packages] }).tap do |u|
|
||||
u.pref[:time_zone] = "utc"
|
||||
u.pref[:time_zone] = "Etc/UTC"
|
||||
|
||||
u.save!
|
||||
end
|
||||
|
||||
@@ -42,7 +42,7 @@ RSpec.describe "Structured meetings CRUD",
|
||||
lastname: "First",
|
||||
member_with_permissions: { project => %i[view_meetings create_meetings edit_meetings delete_meetings manage_agendas
|
||||
view_work_packages] }).tap do |u|
|
||||
u.pref[:time_zone] = "utc"
|
||||
u.pref[:time_zone] = "Etc/UTC"
|
||||
|
||||
u.save!
|
||||
end
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ RSpec.describe "Structured meetings participants",
|
||||
lastname: "First",
|
||||
member_with_permissions: { project => %i[view_meetings create_meetings edit_meetings delete_meetings manage_agendas
|
||||
close_meeting_agendas view_work_packages] }).tap do |u|
|
||||
u.pref[:time_zone] = "utc"
|
||||
u.pref[:time_zone] = "Etc/UTC"
|
||||
|
||||
u.save!
|
||||
end
|
||||
|
||||
@@ -42,7 +42,7 @@ RSpec.describe "Structured meetings links caught by turbo",
|
||||
lastname: "First",
|
||||
member_with_permissions: { project => %i[view_meetings create_meetings edit_meetings delete_meetings manage_agendas
|
||||
view_work_packages] }).tap do |u|
|
||||
u.pref[:time_zone] = "utc"
|
||||
u.pref[:time_zone] = "Etc/UTC"
|
||||
|
||||
u.save!
|
||||
end
|
||||
|
||||
@@ -47,6 +47,8 @@ RSpec.describe MeetingMailer do
|
||||
let(:meeting_agenda) do
|
||||
create(:meeting_agenda, meeting:)
|
||||
end
|
||||
let(:tokyo_offset) { "UTC#{ActiveSupport::TimeZone['Asia/Tokyo'].now.formatted_offset}" }
|
||||
let(:berlin_offset) { "UTC#{ActiveSupport::TimeZone['Europe/Berlin'].now.formatted_offset}" }
|
||||
|
||||
before do
|
||||
User.current = author
|
||||
@@ -88,11 +90,9 @@ RSpec.describe MeetingMailer do
|
||||
context "with a recipient with another time zone" do
|
||||
let!(:preference) { watcher1.pref.update(time_zone: "Asia/Tokyo") }
|
||||
|
||||
it "renders the mail with the correcet locale" do
|
||||
expect(mail.text_part.body).to include("Tokyo")
|
||||
expect(mail.text_part.body).to include("GMT+09:00")
|
||||
expect(mail.html_part.body).to include("Tokyo")
|
||||
expect(mail.html_part.body).to include("GMT+09:00")
|
||||
it "renders the mail with the correct locale" do
|
||||
expect(mail.text_part.body).to include(tokyo_offset)
|
||||
expect(mail.html_part.body).to include(tokyo_offset)
|
||||
|
||||
expect(mail.to).to contain_exactly(watcher1.mail)
|
||||
end
|
||||
@@ -111,8 +111,8 @@ RSpec.describe MeetingMailer do
|
||||
|
||||
it "renders the mail with the correct locale" do
|
||||
expect(mail.html_part.body).to include("11/09/2021 11:00 PM")
|
||||
expect(mail.html_part.body).to include("12:00 AM (GMT+01:00) Europe/Berlin")
|
||||
expect(mail.text_part.body).to include("11/09/2021 11:00 PM-12:00 AM (GMT+01:00) Europe/Berlin")
|
||||
expect(mail.html_part.body).to include("12:00 AM (#{berlin_offset})")
|
||||
expect(mail.text_part.body).to include("11/09/2021 11:00 PM-12:00 AM (#{berlin_offset})")
|
||||
|
||||
expect(mail.to).to contain_exactly(author.mail)
|
||||
end
|
||||
@@ -124,9 +124,9 @@ RSpec.describe MeetingMailer do
|
||||
|
||||
it "renders the mail with the correct locale" do
|
||||
expect(mail.html_part.body).to include("11/10/2021 07:00 AM")
|
||||
expect(mail.html_part.body).to include("08:00 AM (GMT+09:00) Asia/Tokyo")
|
||||
expect(mail.html_part.body).to include("08:00 AM (#{tokyo_offset})")
|
||||
|
||||
expect(mail.text_part.body).to include("11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo")
|
||||
expect(mail.text_part.body).to include("11/10/2021 07:00 AM-08:00 AM (#{tokyo_offset})")
|
||||
|
||||
expect(mail.to).to contain_exactly(watcher1.mail)
|
||||
end
|
||||
@@ -160,7 +160,7 @@ RSpec.describe MeetingMailer do
|
||||
expect(body).to include(meeting.project.name)
|
||||
expect(body).to include(meeting.title)
|
||||
expect(body).to include(meeting.location)
|
||||
expect(body).to include("01/19/2021 11:00 AM-12:00 PM (GMT+01:00) Europe/Berlin")
|
||||
expect(body).to include("01/19/2021 11:00 AM-12:00 PM (#{berlin_offset})")
|
||||
expect(body).to include(meeting.participants[0].name)
|
||||
expect(body).to include(meeting.participants[1].name)
|
||||
end
|
||||
@@ -174,7 +174,7 @@ RSpec.describe MeetingMailer do
|
||||
expect(body).to include(meeting.title)
|
||||
expect(body).to include(meeting.location)
|
||||
expect(body).to include("01/19/2021 11:00 AM")
|
||||
expect(body).to include("12:00 PM (GMT+01:00) Europe/Berlin")
|
||||
expect(body).to include("12:00 PM (#{berlin_offset})")
|
||||
expect(body).to include(meeting.participants[0].name)
|
||||
expect(body).to include(meeting.participants[1].name)
|
||||
end
|
||||
@@ -207,9 +207,9 @@ RSpec.describe MeetingMailer do
|
||||
let(:mail) { described_class.icalendar_notification(meeting, watcher1, author) }
|
||||
|
||||
it "renders the mail with the correct locale" do
|
||||
expect(mail.text_part.body).to include("01/19/2021 07:00 PM-08:00 PM (GMT+09:00) Asia/Tokyo")
|
||||
expect(mail.text_part.body).to include("01/19/2021 07:00 PM-08:00 PM (#{tokyo_offset})")
|
||||
expect(mail.html_part.body).to include("01/19/2021 07:00 PM")
|
||||
expect(mail.html_part.body).to include("08:00 PM (GMT+09:00) Asia/Tokyo")
|
||||
expect(mail.html_part.body).to include("08:00 PM (#{tokyo_offset})")
|
||||
|
||||
expect(mail.to).to contain_exactly(watcher1.mail)
|
||||
end
|
||||
@@ -227,9 +227,9 @@ RSpec.describe MeetingMailer do
|
||||
let(:mail) { described_class.icalendar_notification(meeting, author, author) }
|
||||
|
||||
it "renders the mail with the correct locale" do
|
||||
expect(mail.text_part.body).to include("11/09/2021 11:00 PM-12:00 AM (GMT+01:00) Europe/Berlin")
|
||||
expect(mail.text_part.body).to include("11/09/2021 11:00 PM-12:00 AM (#{berlin_offset})")
|
||||
expect(mail.html_part.body).to include("11/09/2021 11:00 PM")
|
||||
expect(mail.html_part.body).to include("12:00 AM (GMT+01:00) Europe/Berlin")
|
||||
expect(mail.html_part.body).to include("12:00 AM (#{berlin_offset})")
|
||||
|
||||
expect(mail.to).to contain_exactly(author.mail)
|
||||
end
|
||||
@@ -240,8 +240,8 @@ RSpec.describe MeetingMailer do
|
||||
let!(:preference) { watcher1.pref.update(time_zone: "Asia/Tokyo") }
|
||||
|
||||
it "renders the mail with the correct locale" do
|
||||
expect(mail.text_part.body).to include("11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo")
|
||||
expect(mail.html_part.body).to include("11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo")
|
||||
expect(mail.text_part.body).to include("11/10/2021 07:00 AM-08:00 AM (#{tokyo_offset})")
|
||||
expect(mail.html_part.body).to include("11/10/2021 07:00 AM-08:00 AM (#{tokyo_offset})")
|
||||
|
||||
expect(mail.to).to contain_exactly(watcher1.mail)
|
||||
end
|
||||
@@ -253,8 +253,9 @@ RSpec.describe MeetingMailer do
|
||||
expect(body).to include(meeting.project.name)
|
||||
expect(body).to include(meeting.title)
|
||||
expect(body).to include(i18n.format_date(meeting.start_date))
|
||||
expect(body).to include(i18n.format_time(meeting.start_time, false))
|
||||
expect(body).to include(i18n.format_time(meeting.end_time, false))
|
||||
expect(body).to include(i18n.format_time(meeting.start_time, include_date: false))
|
||||
expect(body).to include(i18n.format_time(meeting.end_time, include_date: false))
|
||||
expect(body).to include(i18n.formatted_time_zone_offset)
|
||||
expect(body).to include(meeting.participants[0].name)
|
||||
expect(body).to include(meeting.participants[1].name)
|
||||
end
|
||||
|
||||
@@ -79,7 +79,7 @@ module XlsExport
|
||||
def xls_export_filename
|
||||
sane_filename(
|
||||
"#{Setting.app_title} #{spreadsheet_title} \
|
||||
#{format_time_as_date(Time.zone.now, '%Y-%m-%d')}.xls"
|
||||
#{format_time_as_date(Time.zone.now, format: '%Y-%m-%d')}.xls"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -62,8 +62,8 @@ RSpec.describe API::V3::UserPreferences::UserPreferenceRepresenter,
|
||||
context "without a timezone set" do
|
||||
let(:preference) { build(:user_preference, time_zone: "") }
|
||||
|
||||
it "shows the timeZone as nil" do
|
||||
expect(subject).to be_json_eql(nil.to_json).at_path("timeZone")
|
||||
it "shows the timeZone as utc" do
|
||||
expect(subject).to be_json_eql("Etc/UTC".to_json).at_path("timeZone")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -35,43 +35,35 @@ module OpenProject
|
||||
let(:format) { "%d/%m/%Y" }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
|
||||
after do
|
||||
Time.zone = nil
|
||||
end
|
||||
describe "#format_time_as_date" do
|
||||
current_user { build_stubbed(:user, preferences: { time_zone: user_time_zone }) }
|
||||
|
||||
describe "with user time zone" do
|
||||
before do
|
||||
login_as user
|
||||
allow(user).to receive(:time_zone).and_return(ActiveSupport::TimeZone["Athens"])
|
||||
describe "with user time zone" do
|
||||
let(:user_time_zone) { "Europe/Athens" }
|
||||
|
||||
it "returns a date string in the user timezone for a utc timestamp" do
|
||||
time = ActiveSupport::TimeZone["UTC"].local(2013, 6, 30, 23, 59)
|
||||
expect(format_time_as_date(time, format:)).to eq "01/07/2013"
|
||||
end
|
||||
|
||||
it "returns a date string in the user timezone for a non-utc timestamp" do
|
||||
time = ActiveSupport::TimeZone["Berlin"].local(2013, 6, 30, 23, 59)
|
||||
expect(format_time_as_date(time, format:)).to eq "01/07/2013"
|
||||
end
|
||||
end
|
||||
|
||||
it "returns a date in the user timezone for a utc timestamp" do
|
||||
Time.zone = "UTC"
|
||||
time = Time.zone.local(2013, 6, 30, 23, 59)
|
||||
expect(format_time_as_date(time, format)).to eq "01/07/2013"
|
||||
end
|
||||
describe "without user time zone" do
|
||||
let(:user_time_zone) { "" }
|
||||
|
||||
it "returns a date in the user timezone for a non-utc timestamp" do
|
||||
Time.zone = "Berlin"
|
||||
time = Time.zone.local(2013, 6, 30, 23, 59)
|
||||
expect(format_time_as_date(time, format)).to eq "01/07/2013"
|
||||
end
|
||||
end
|
||||
it "returns a date string in the utc timezone for a utc timestamp" do
|
||||
time = ActiveSupport::TimeZone["UTC"].local(2013, 6, 30, 23, 59)
|
||||
expect(format_time_as_date(time, format:)).to eq "30/06/2013"
|
||||
end
|
||||
|
||||
describe "without user time zone" do
|
||||
before { allow(User.current).to receive(:time_zone).and_return(nil) }
|
||||
|
||||
it "returns a date in the local system timezone for a utc timestamp" do
|
||||
Time.zone = "UTC"
|
||||
time = Time.zone.local(2013, 6, 30, 23, 59)
|
||||
allow(time).to receive(:localtime).and_return(ActiveSupport::TimeZone["Athens"].local(2013, 7, 1, 1, 59))
|
||||
expect(format_time_as_date(time, format)).to eq "01/07/2013"
|
||||
end
|
||||
|
||||
it "returns a date in the original timezone for a non-utc timestamp" do
|
||||
Time.zone = "Berlin"
|
||||
time = Time.zone.local(2013, 6, 30, 23, 59)
|
||||
expect(format_time_as_date(time, format)).to eq "30/06/2013"
|
||||
it "returns a date string in the utc timezone for a non-utc timestamp" do
|
||||
time = ActiveSupport::TimeZone["Berlin"].local(2013, 6, 30, 23, 59)
|
||||
expect(format_time_as_date(time, format:)).to eq "30/06/2013"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -271,7 +263,10 @@ module OpenProject
|
||||
time_format: "%H %M",
|
||||
date_format: "%d %m %Y"
|
||||
} do
|
||||
let!(:now) { Time.parse("2011-02-20 15:45:22") }
|
||||
let(:user_time_zone) { "" }
|
||||
let(:now) { Time.zone.parse("2011-02-20 15:45:22") }
|
||||
|
||||
current_user { build_stubbed(:user, preferences: { time_zone: user_time_zone }) }
|
||||
|
||||
it "with date and hours" do
|
||||
expect(format_time(now))
|
||||
@@ -279,18 +274,33 @@ module OpenProject
|
||||
end
|
||||
|
||||
it "with only hours" do
|
||||
expect(format_time(now, false))
|
||||
expect(format_time(now, include_date: false))
|
||||
.to eql now.strftime("%H %M")
|
||||
end
|
||||
|
||||
it "with a utc to date and hours" do
|
||||
expect(format_time(now.utc))
|
||||
.to eql now.localtime.strftime("%d %m %Y %H %M")
|
||||
it "renders correctly for only hours and when providing a custom format" do
|
||||
expect(format_time(now, include_date: false, format: "%H:%M"))
|
||||
.to eql now.strftime("%H:%M")
|
||||
end
|
||||
|
||||
it "with a utce to only hours" do
|
||||
expect(format_time(now.utc, false))
|
||||
.to eql now.localtime.strftime("%H %M")
|
||||
context "with another time zone configured for the user" do
|
||||
# Kathmandu has a +05:45 offset
|
||||
let(:user_time_zone) { "Kathmandu" }
|
||||
|
||||
it "renders correctly for data and hours" do
|
||||
expect(format_time(now))
|
||||
.to eql "20 02 2011 21 30"
|
||||
end
|
||||
|
||||
it "renders correctly for only hours" do
|
||||
expect(format_time(now, include_date: false))
|
||||
.to eql "21 30"
|
||||
end
|
||||
|
||||
it "renders correctly for only hours and when providing a custom format" do
|
||||
expect(format_time(now, include_date: false, format: "%H:%M"))
|
||||
.to eql "21:30"
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different format defined", with_settings: {
|
||||
@@ -303,7 +313,7 @@ module OpenProject
|
||||
end
|
||||
|
||||
it "renders only hours" do
|
||||
expect(format_time(now, false))
|
||||
expect(format_time(now, include_date: false))
|
||||
.to eql "15:45"
|
||||
end
|
||||
end
|
||||
@@ -318,7 +328,7 @@ module OpenProject
|
||||
end
|
||||
|
||||
it "falls back to default for only hours" do
|
||||
expect(format_time(now, false))
|
||||
expect(format_time(now, include_date: false))
|
||||
.to eql "03:45 PM"
|
||||
end
|
||||
|
||||
@@ -333,7 +343,7 @@ module OpenProject
|
||||
|
||||
it "raises no error for only hours" do
|
||||
described_class.with_locale lang do
|
||||
expect { format_time(now, false) }
|
||||
expect { format_time(now, include_date: false) }
|
||||
.not_to raise_error
|
||||
end
|
||||
end
|
||||
@@ -351,7 +361,7 @@ module OpenProject
|
||||
end
|
||||
|
||||
it "falls back to default for only hours" do
|
||||
expect(format_time(now, false))
|
||||
expect(format_time(now, include_date: false))
|
||||
.to eql "03:45 PM"
|
||||
end
|
||||
end
|
||||
@@ -366,12 +376,53 @@ module OpenProject
|
||||
end
|
||||
|
||||
it "falls back to default for only hours" do
|
||||
expect(format_time(now, false))
|
||||
expect(format_time(now, include_date: false))
|
||||
.to eql "15:45"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#formatted_time_zone_offset" do
|
||||
current_user { build_stubbed(:user, preferences: { time_zone: user_time_zone }) }
|
||||
let(:user_time_zone) { "" }
|
||||
|
||||
let(:berlin_gmt) { ActiveSupport::TimeZone["Europe/Berlin"].now.utc_offset == 7200 ? "UTC+02:00" : "UTC+01:00" }
|
||||
|
||||
context "with the current user having set a time zone" do
|
||||
let(:user_time_zone) { "Europe/Berlin" }
|
||||
|
||||
it "renders the time zone of the user" do
|
||||
expect(formatted_time_zone_offset).to eql berlin_gmt
|
||||
end
|
||||
end
|
||||
|
||||
context "without the current user having a time zone and no default one configured" do
|
||||
let(:user_time_zone) { "" }
|
||||
|
||||
it "renders the UTC time zone" do
|
||||
expect(formatted_time_zone_offset).to eql "UTC+00:00"
|
||||
end
|
||||
end
|
||||
|
||||
context "without the current user having a time zone but with a default one configured",
|
||||
with_settings: { user_default_timezone: "Europe/Berlin" } do
|
||||
let(:user_time_zone) { "" }
|
||||
|
||||
it "renders the default time zone" do
|
||||
expect(formatted_time_zone_offset).to eql berlin_gmt
|
||||
end
|
||||
end
|
||||
|
||||
context "without the current user having a time zone and also a default one configured",
|
||||
with_settings: { user_default_timezone: "America/Atlanta" } do
|
||||
let(:user_time_zone) { "Europe/Berlin" }
|
||||
|
||||
it "renders the default time zone" do
|
||||
expect(formatted_time_zone_offset).to eql berlin_gmt
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "day names" do
|
||||
valid_languages.each do |lang|
|
||||
context "for locale #{lang}" do
|
||||
|
||||
@@ -48,7 +48,7 @@ RSpec.describe DeletedUser do
|
||||
end
|
||||
|
||||
describe "#time_zone" do
|
||||
it { expect(user.time_zone).to be_nil }
|
||||
it { expect(user.time_zone).to eql ActiveSupport::TimeZone["Etc/UTC"] }
|
||||
end
|
||||
|
||||
describe "#rss_key" do
|
||||
|
||||
@@ -222,4 +222,48 @@ RSpec.describe UserPreference do
|
||||
expect(subject[:auto_hide_popups]).to eql(value_auto_hide_popups)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#time_zone" do
|
||||
context "with a time zone set and a default configured", with_settings: { user_default_timezone: "America/Los_Angeles" } do
|
||||
let(:settings) { { "time_zone" => "Africa/Algiers" } }
|
||||
|
||||
it "returns the time zone set" do
|
||||
expect(preference.time_zone).to eql "Africa/Algiers"
|
||||
end
|
||||
end
|
||||
|
||||
context "with no time zone configured but a default", with_settings: { user_default_timezone: "America/Los_Angeles" } do
|
||||
it "returns the default time zone" do
|
||||
expect(preference.time_zone).to eql "America/Los_Angeles"
|
||||
end
|
||||
end
|
||||
|
||||
context "with neiter a time zone configured nor a default one", with_settings: { user_default_timezone: "" } do
|
||||
it "returns UTC" do
|
||||
expect(preference.time_zone).to eql "Etc/UTC"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#time_zone?" do
|
||||
context "with a time zone set and a default configured", with_settings: { user_default_timezone: "America/Los_Angeles" } do
|
||||
let(:settings) { { "time_zone" => "Africa/Algiers" } }
|
||||
|
||||
it "is true" do
|
||||
expect(preference).to be_time_zone
|
||||
end
|
||||
end
|
||||
|
||||
context "with no time zone configured but a default", with_settings: { user_default_timezone: "America/Los_Angeles" } do
|
||||
it "is false" do
|
||||
expect(preference).not_to be_time_zone
|
||||
end
|
||||
end
|
||||
|
||||
context "with neiter a time zone configured nor a default one", with_settings: { user_default_timezone: "" } do
|
||||
it "is false" do
|
||||
expect(preference).not_to be_time_zone
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -823,6 +823,39 @@ RSpec.describe User do
|
||||
end
|
||||
end
|
||||
|
||||
describe "#time_zone" do
|
||||
let(:user) { build(:user, preferences:) }
|
||||
|
||||
context "with an existing time zone in the prefs" do
|
||||
let(:preferences) { { "time_zone" => "Europe/Athens" } }
|
||||
|
||||
it "returns the matching ActiveSupport::TimeZone" do
|
||||
expect(user.time_zone)
|
||||
.to eql ActiveSupport::TimeZone["Europe/Athens"]
|
||||
end
|
||||
end
|
||||
|
||||
context "with an invalid time zone" do
|
||||
# Would need to be Etc/UTC or UTC to be valid
|
||||
let(:preferences) { { "time_zone" => "utc" } }
|
||||
|
||||
it "returns the utc ActiveSupport::TimeZone" do
|
||||
expect(user.time_zone)
|
||||
.to eql ActiveSupport::TimeZone["Etc/UTC"]
|
||||
end
|
||||
end
|
||||
|
||||
context "without a time zone" do
|
||||
# Would need to be Etc/UTC or UTC to be valid
|
||||
let(:preferences) { {} }
|
||||
|
||||
it "returns the utc ActiveSupport::TimeZone" do
|
||||
expect(user.time_zone)
|
||||
.to eql ActiveSupport::TimeZone["Etc/UTC"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_by_mail" do
|
||||
let!(:user1) { create(:user, mail: "foo+test@example.org") }
|
||||
let!(:user2) { create(:user, mail: "foo@example.org") }
|
||||
|
||||
@@ -32,8 +32,8 @@ RSpec.describe User, "default time zone" do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
context "with no system default set" do
|
||||
it "is not set" do
|
||||
expect(user.pref.time_zone).to be_nil
|
||||
it "is still set to Etc/UTC as that will be calculated with internally" do
|
||||
expect(user.pref.time_zone).to eq "Etc/UTC"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ RSpec.describe WorkPackage::PDFExport::WorkPackageListToPdf do
|
||||
end
|
||||
end
|
||||
let(:export_time) { DateTime.new(2024, 4, 22, 12, 37) }
|
||||
let(:export_time_formatted) { format_time(export_time, true) }
|
||||
let(:export_time_formatted) { format_time(export_time, include_date: true) }
|
||||
let(:export) do
|
||||
login_as(user)
|
||||
work_packages
|
||||
|
||||
@@ -62,7 +62,7 @@ RSpec.describe WorkPackage::PDFExport::WorkPackageListToPdf do
|
||||
member_with_permissions: { project => %w[view_work_packages export_work_packages] })
|
||||
end
|
||||
let(:export_time) { DateTime.new(2023, 6, 30, 23, 59) }
|
||||
let(:export_time_formatted) { format_time(export_time, true) }
|
||||
let(:export_time_formatted) { format_time(export_time, include_date: true) }
|
||||
let(:work_package_parent) do
|
||||
create(:work_package,
|
||||
project:,
|
||||
|
||||
@@ -91,7 +91,7 @@ RSpec.describe WorkPackage::PDFExport::WorkPackageToPdf do
|
||||
let(:category) { create(:category, project:, name: "Demo") }
|
||||
let(:version) { create(:version, project:) }
|
||||
let(:export_time) { DateTime.new(2023, 6, 30, 23, 59) }
|
||||
let(:export_time_formatted) { format_time(export_time, true) }
|
||||
let(:export_time_formatted) { format_time(export_time, include_date: true) }
|
||||
let(:image_path) { Rails.root.join("spec/fixtures/files/image.png") }
|
||||
let(:priority) { create(:priority_normal) }
|
||||
let(:image_attachment) { Attachment.new author: user, file: File.open(image_path) }
|
||||
|
||||
Reference in New Issue
Block a user