Skip to content

Commit aa67a32

Browse files
Merge remote-tracking branch 'upstream/master' into ras-22643
2 parents 58554ca + 355f71b commit aa67a32

22 files changed

+717
-729
lines changed

assets/vue/components/basecomponents/BaseTinyEditor.vue

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,14 +214,15 @@ const editorConfig = computed(() => ({
214214
...defaultEditorConfig,
215215
...props.editorConfig,
216216
file_picker_callback: filePickerCallback,
217+
setup(editor) {
218+
editor.on("GetContent", (e) => {
219+
if (!e.content.includes("tiny-content")) {
220+
e.content = `<div class="tiny-content">${e.content}</div>`
221+
}
222+
})
223+
},
217224
}))
218225
219-
watch(modelValue, (newValue) => {
220-
if (newValue && !newValue.includes("tiny-content")) {
221-
modelValue.value = `<div class="tiny-content">${newValue}</div>`
222-
}
223-
})
224-
225226
async function filePickerCallback(callback, value, meta) {
226227
let url = getUrlForTinyEditor()
227228
if ("image" === meta.filetype) {

assets/vue/components/social/SocialWallPost.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
/>
1414

1515
<div class="flex flex-col">
16-
<div v-if="null === post.userReceiver || post.sender['@id'] === post.userReceiver['@id']">
16+
<div v-if="!post.userReceiver || post.sender['@id'] === post.userReceiver?.['@id']">
1717
<BaseAppLink :to="{ name: 'SocialWall', query: { id: post.sender['@id'] } }">
1818
{{ post.sender.fullName }}
1919
</BaseAppLink>

assets/vue/composables/formatDate.js

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
import { DateTime } from "luxon"
22
import { useLocale } from "./locale"
3+
import { usePlatformConfig } from "../store/platformConfig"
4+
import { useSecurityStore } from "../store/securityStore"
35

46
export function useFormatDate() {
57
const { appParentLocale } = useLocale()
8+
const platformConfigStore = usePlatformConfig()
9+
const securityStore = useSecurityStore()
10+
11+
function getCurrentTimezone() {
12+
const allowUserTimezone = platformConfigStore.getSetting("profile.use_users_timezone") === "true"
13+
const userTimezone = securityStore.user?.timezone
14+
const platformTimezone = platformConfigStore.getSetting("platform.timezone")
15+
16+
if (allowUserTimezone && userTimezone) {
17+
return userTimezone
18+
}
19+
20+
if (platformTimezone && platformTimezone !== "false") {
21+
return platformTimezone
22+
}
23+
24+
return Intl.DateTimeFormat().resolvedOptions().timeZone
25+
}
626

7-
/**
8-
* @param {Date|string} datetime
9-
* @returns {DateTime|null}
10-
*/
1127
function getDateTimeObject(datetime) {
1228
if (!datetime) {
1329
return null
@@ -16,16 +32,18 @@ export function useFormatDate() {
1632
let dt
1733

1834
if (typeof datetime === "string") {
19-
dt = DateTime.fromISO(datetime)
20-
} else if (typeof datetime === "object") {
21-
dt = DateTime.fromJSDate(datetime)
35+
dt = DateTime.fromISO(datetime, { zone: "utc" })
36+
} else if (datetime instanceof Date) {
37+
dt = DateTime.fromJSDate(datetime, { zone: "utc" })
38+
} else {
39+
return null
2240
}
2341

2442
if (!dt.isValid) {
2543
return null
2644
}
2745

28-
return dt.setLocale(appParentLocale.value)
46+
return dt.setZone(getCurrentTimezone()).setLocale(appParentLocale.value)
2947
}
3048

3149
const abbreviatedDatetime = (datetime) =>
@@ -34,10 +52,12 @@ export function useFormatDate() {
3452
month: "long",
3553
})
3654

37-
const relativeDatetime = (datetime) => getDateTimeObject(datetime)?.toRelative()
55+
const relativeDatetime = (datetime) =>
56+
getDateTimeObject(datetime)?.toRelative()
3857

3958
return {
4059
abbreviatedDatetime,
4160
relativeDatetime,
61+
getCurrentTimezone,
4262
}
4363
}

assets/vue/utils/dates.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1-
const { DateTime } = require("luxon")
1+
import { DateTime } from "luxon"
2+
import { useFormatDate } from "../composables/formatDate"
23

3-
const formatDateTime = function (date) {
4-
if (!date) return null
4+
const { getCurrentTimezone } = useFormatDate()
55

6-
return DateTime(date).format("DD/MM/YYYY")
6+
/**
7+
* Format a JS Date object to string using the current or provided timezone.
8+
* @param {Date} date - JavaScript Date object
9+
* @param {string} [timezone] - Optional timezone (e.g. "America/Lima")
10+
* @returns {string}
11+
*/
12+
const formatDateTime = function (date, timezone) {
13+
if (!date) return ""
14+
const tz = timezone || getCurrentTimezone()
15+
return DateTime.fromJSDate(date, { zone: "utc" }).setZone(tz).toFormat("dd/LL/yyyy HH:mm")
716
}
817

9-
const formatDateTimeFromISO = function (dateStr) {
18+
/**
19+
* Format an ISO string to readable string using the current or provided timezone.
20+
* @param {string} dateStr - ISO date string (e.g. "2025-06-17T14:00:00Z")
21+
* @param {string} [timezone] - Optional timezone
22+
* @returns {string}
23+
*/
24+
const formatDateTimeFromISO = function (dateStr, timezone) {
1025
if (!dateStr) return ""
11-
12-
return DateTime.fromISO(dateStr).toFormat("dd/LL/yyyy HH:mm")
26+
const tz = timezone || getCurrentTimezone()
27+
return DateTime.fromISO(dateStr, { zone: "utc" }).setZone(tz).toFormat("dd/LL/yyyy HH:mm")
1328
}
1429

1530
export { formatDateTime, formatDateTimeFromISO }

assets/vue/views/ccalendarevent/CCalendarEventList.vue

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,15 @@ import { useCalendarEvent } from "../../composables/calendar/calendarEvent"
150150
import resourceLinkService from "../../services/resourceLinkService"
151151
import { useSecurityStore } from "../../store/securityStore"
152152
import { useCourseSettings } from "../../store/courseSettingStore"
153+
import { DateTime } from "luxon"
153154
154155
const store = useStore()
155156
const securityStore = useSecurityStore()
156157
const confirm = useConfirm()
157158
const cidReqStore = useCidReqStore()
158159
159160
const { course, session, group } = storeToRefs(cidReqStore)
160-
161-
const { abbreviatedDatetime } = useFormatDate()
162-
161+
const { abbreviatedDatetime, getCurrentTimezone } = useFormatDate()
163162
const { showAddButton } = useCalendarActionButtons()
164163
165164
const { isEditableByUser, allowSubscribeToEvent, allowUnsubscribeToEvent } = useCalendarEvent()
@@ -235,13 +234,15 @@ async function getCalendarEvents({ start, end }) {
235234
const calendarEvents = await cCalendarEventService.findAll({ params }).then((response) => response.json())
236235
237236
return calendarEvents["hydra:member"].map((event) => {
238-
let color = event.color || "#007BFF"
237+
const timezone = getCurrentTimezone()
238+
const start = DateTime.fromISO(event.startDate, { zone: "utc" }).setZone(timezone)
239+
const end = DateTime.fromISO(event.endDate, { zone: "utc" }).setZone(timezone)
239240
240241
return {
241242
...event,
242-
start: event.startDate,
243-
end: event.endDate,
244-
color,
243+
start: start.toString(),
244+
end: end.toString(),
245+
color: event.color || "#007BFF",
245246
}
246247
})
247248
}
@@ -257,16 +258,9 @@ const showAddEventDialog = () => {
257258
258259
dialog.value = true
259260
}
260-
261-
const goToMyStudentsSchedule = () => {
262-
window.location.href = "/main/calendar/planification.php"
263-
}
264-
265-
const goToSessionPanning = () => {
266-
window.location.href = "/main/my_space/calendar_plan.php"
267-
}
268-
261+
const timezone = getCurrentTimezone()
269262
const calendarOptions = ref({
263+
timeZone: timezone,
270264
plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
271265
locales: allLocales,
272266
locale: calendarLocale?.code ?? "en-GB",

public/main/inc/lib/database.lib.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ public static function store_result(\Doctrine\DBAL\Result $result, $option = 'BO
312312
* @throws \Doctrine\DBAL\Exception
313313
* @throws Exception
314314
*/
315-
public static function insert(string $table_name, array $attributes, bool $show_query = false): bool|int
315+
public static function insert(string $table_name, array $attributes, bool $show_query = false, array $options = []): bool|int
316316
{
317317
if (empty($attributes) || empty($table_name)) {
318318
return false;
@@ -321,8 +321,9 @@ public static function insert(string $table_name, array $attributes, bool $show_
321321
$params = array_keys($attributes);
322322

323323
if (!empty($params)) {
324-
$sql = 'INSERT INTO '.$table_name.' ('.implode(',', $params).')
325-
VALUES (:'.implode(', :', $params).')';
324+
$prefix = (!empty($options['ignore'])) ? 'INSERT IGNORE INTO' : 'INSERT INTO';
325+
$sql = $prefix.' '.$table_name.' ('.implode(',', $params).')
326+
VALUES (:'.implode(', :', $params).')';
326327

327328
if ($show_query) {
328329
var_dump($sql);

public/main/inc/lib/internationalization.lib.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -192,29 +192,28 @@ function api_get_timezones()
192192
*
193193
* @return string The timezone chosen
194194
*/
195-
function api_get_timezone()
195+
function api_get_timezone(): string
196196
{
197197
$timezone = Session::read('system_timezone');
198198
if (empty($timezone)) {
199-
// First, get the default timezone of the server
199+
// 1. Default server timezone
200200
$timezone = date_default_timezone_get();
201-
// Second, see if a timezone has been chosen for the platform
202-
$timezoneFromSettings = api_get_setting('platform.timezone', false, 'timezones');
203201

204-
if (null != $timezoneFromSettings) {
202+
// 2. Platform-specific timezone setting (overrides server default)
203+
$timezoneFromSettings = api_get_setting('platform.timezone', false, 'timezones');
204+
if (!empty($timezoneFromSettings)) {
205205
$timezone = $timezoneFromSettings;
206206
}
207207

208-
// If allowed by the administrator
208+
// 3. User-specific timezone if allowed
209209
$allowUserTimezones = api_get_setting('profile.use_users_timezone', false, 'timezones');
210210
$userId = api_get_user_id();
211211

212212
if ('true' === $allowUserTimezones && !empty($userId)) {
213-
// Get the timezone based on user preference, if it exists
214-
$newExtraField = new ExtraFieldValue('user');
215-
$data = $newExtraField->get_values_by_handler_and_field_variable($userId, 'timezone');
216-
if (!empty($data) && isset($data['timezone']) && !empty($data['timezone'])) {
217-
$timezone = $data['timezone'];
213+
$user = api_get_user_entity($userId);
214+
215+
if ($user && $user->getTimezone()) {
216+
$timezone = $user->getTimezone();
218217
}
219218
}
220219
Session::write('system_timezone', $timezone);

0 commit comments

Comments
 (0)