fetch remote calendar and show on FullCalendar frame

This commit is contained in:
Julien Fastré 2022-05-23 15:00:32 +02:00
parent e2052fe71d
commit f825c69ce5
9 changed files with 151 additions and 30 deletions

View File

@ -269,6 +269,10 @@ class CalendarController extends AbstractController
*/ */
public function newAction(Request $request): Response public function newAction(Request $request): Response
{ {
if (!$this->remoteCalendarConnector->isReady()) {
return $this->remoteCalendarConnector->getMakeReadyResponse($request->getUri());
}
$view = null; $view = null;
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();

View File

@ -13,6 +13,8 @@ namespace Chill\CalendarBundle\Controller;
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface; use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Serializer\Model\Collection;
use DateTimeImmutable; use DateTimeImmutable;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -30,8 +32,11 @@ class RemoteCalendarProxyController
private SerializerInterface $serializer; private SerializerInterface $serializer;
public function __construct(RemoteCalendarConnectorInterface $remoteCalendarConnector, SerializerInterface $serializer) private PaginatorFactory $paginatorFactory;
public function __construct(PaginatorFactory $paginatorFactory, RemoteCalendarConnectorInterface $remoteCalendarConnector, SerializerInterface $serializer)
{ {
$this->paginatorFactory = $paginatorFactory;
$this->remoteCalendarConnector = $remoteCalendarConnector; $this->remoteCalendarConnector = $remoteCalendarConnector;
$this->serializer = $serializer; $this->serializer = $serializer;
} }
@ -41,30 +46,38 @@ class RemoteCalendarProxyController
*/ */
public function listEventForCalendar(User $user, Request $request): Response public function listEventForCalendar(User $user, Request $request): Response
{ {
if ($request->query->has('startDate')) { if (!$request->query->has('dateFrom')) {
$startDate = DateTimeImmutable::createFromFormat('Y-m-d\TH:i:s', $request->query->get('startDate') . 'T00:00:00'); throw new BadRequestHttpException('You must provide a dateFrom parameter');
if (false === $startDate) {
throw new BadRequestHttpException('startDate on bad format');
}
} else {
throw new BadRequestHttpException('startDate not provided');
} }
if ($request->query->has('endDate')) { if (false === $dateFrom = DateTimeImmutable::createFromFormat(
$endDate = DateTimeImmutable::createFromFormat('Y-m-d\TH:i:s', $request->query->get('endDate') . 'T23:59:59'); DateTimeImmutable::ATOM,
$request->query->get('dateFrom')
if (false === $endDate) { )) {
throw new BadRequestHttpException('endDate on bad format'); throw new BadRequestHttpException('dateFrom not parsable');
}
} else {
throw new BadRequestHttpException('endDate not provided');
} }
$events = $this->remoteCalendarConnector->listEventsForUser($user, $startDate, $endDate); if (!$request->query->has('dateTo')) {
throw new BadRequestHttpException('You must provide a dateTo parameter');
}
if (false === $dateTo = DateTimeImmutable::createFromFormat(
DateTimeImmutable::ATOM,
$request->query->get('dateTo')
)) {
throw new BadRequestHttpException('dateTo not parsable');
}
$events = $this->remoteCalendarConnector->listEventsForUser($user, $dateFrom, $dateTo);
$paginator = $this->paginatorFactory->create(count($events));
if (count($events) > 0) {
$paginator->setItemsPerPage($paginator->getTotalItems());
}
$collection = new Collection($events, $paginator);
return new JsonResponse( return new JsonResponse(
$this->serializer->serialize($events, 'json', ['groups' => ['read']]), $this->serializer->serialize($collection, 'json', ['groups' => ['read']]),
JsonResponse::HTTP_OK, JsonResponse::HTTP_OK,
[], [],
true true

View File

@ -35,7 +35,7 @@ export default {
}, },
remoteShow: { remoteShow: {
set (value) { set (value) {
this.$store.commit('showUserOnCalendar', {user: this.user, remote: value}); this.$store.commit('showUserOnCalendar', {user: this.user, remotes: value});
}, },
get() { get() {
return this.$store.getters.isRemoteShownOnCalendarForUser(this.user); return this.$store.getters.isRemoteShownOnCalendarForUser(this.user);

View File

@ -33,7 +33,16 @@ const fetchCalendarRangeForUser = (user, start, end) => {
return fetchResults(uri, {dateFrom, dateTo}); return fetchResults(uri, {dateFrom, dateTo});
} }
const fetchCalendarRemoteForUser = (user, start, end) => {
const uri = `/api/1.0/calendar/proxy/calendar/by-user/${user.id}/events`;
const dateFrom = datetimeToISO(start);
const dateTo = datetimeToISO(end);
return fetchResults(uri, {dateFrom, dateTo});
}
export { export {
whoami, whoami,
fetchCalendarRangeForUser, fetchCalendarRangeForUser,
fetchCalendarRemoteForUser,
}; };

View File

@ -4,7 +4,10 @@ import {
removeIdFromValue, removeIdFromValue,
mapEntity mapEntity
} from './utils'; } from './utils';
import {fetchCalendarRangeForUser} from './../api'; import {
fetchCalendarRangeForUser,
fetchCalendarRemoteForUser,
} from './../api';
export default { export default {
setCurrentDatesView({ commit, dispatch }, {start, end}) { setCurrentDatesView({ commit, dispatch }, {start, end}) {
@ -21,8 +24,16 @@ export default {
for (const uid of state.currentView.users.keys()) { for (const uid of state.currentView.users.keys()) {
console.log('fetchCalendarEventsFor', uid); console.log('fetchCalendarEventsFor', uid);
promises.push( promises.push(
dispatch('fetchCalendarRangeForUser', dispatch(
{user: state.usersData.get(uid).user, start: state.currentView.start, end: state.currentView.end}) 'fetchCalendarRangeForUser',
{user: state.usersData.get(uid).user, start: state.currentView.start, end: state.currentView.end}
)
);
promises.push(
dispatch(
'fetchCalendarRemotesForUser',
{user: state.usersData.get(uid).user, start: state.currentView.start, end: state.currentView.end}
)
); );
} }
@ -37,6 +48,15 @@ export default {
}); });
} }
}, },
fetchCalendarRemotesForUser({ commit, getters }, { user, start, end }) {
if (!getters.isCalendarRemoteLoadedForUser({user, start, end})) {
return fetchCalendarRemoteForUser(user, start, end).then((remotes) => {
commit('addCalendarRemotesForUser', {user, remotes, start, end});
return Promise.resolve();
});
}
},
addPersonsInvolved({ commit, dispatch }, payload) { addPersonsInvolved({ commit, dispatch }, payload) {
console.log('### action addPersonsInvolved', payload.result.type); console.log('### action addPersonsInvolved', payload.result.type);
switch (payload.result.type) { switch (payload.result.type) {
@ -51,7 +71,7 @@ export default {
case 'user': case 'user':
let aUsers = document.getElementById("chill_activitybundle_activity_users"); let aUsers = document.getElementById("chill_activitybundle_activity_users");
aUsers.value = addIdToValue(aUsers.value, payload.result.id); aUsers.value = addIdToValue(aUsers.value, payload.result.id);
commit('showUserOnCalendar', {user: payload.result, ranges: false, remote: true}); commit('showUserOnCalendar', {user: payload.result, ranges: false, remotes: true});
dispatch('fetchCalendarEvents'); dispatch('fetchCalendarEvents');
break; break;
}; };

View File

@ -47,7 +47,7 @@ export default {
if (kinds.ranges && userData.calendarRanges.length > 0) { if (kinds.ranges && userData.calendarRanges.length > 0) {
console.log('adding ranges for user', userId); console.log('adding ranges for user', userId);
const s = { const s = {
'id': `ranges_${userId}`, id: `ranges_${userId}`,
events: userData.calendarRanges, events: userData.calendarRanges,
color: userData.mainColor, color: userData.mainColor,
backgroundColor: 'white', backgroundColor: 'white',
@ -61,6 +61,22 @@ export default {
} else { } else {
console.log('not adding ranges for user', userId); console.log('not adding ranges for user', userId);
} }
if (kinds.remotes && userData.remotes.length > 0) {
console.log('adding remotes for user', userId);
const s = {
'id': `remote_${userId}`,
events: userData.remotes,
color: userData.mainColor,
textColor: 'black',
editable: false,
};
console.log('remote source', s);
sources.push(s);
} else {
console.log('not adding remotes for user', userId);
}
} }
console.log('eventSources', sources); console.log('eventSources', sources);
@ -112,6 +128,27 @@ export default {
return false; return false;
}, },
/**
* return true if there was a fetch query for event between this date (start and end),
* those date are included.
*
* @param state
* @param getters
* @returns {(function({user: *, start: *, end: *}): (boolean))|*}
*/
isCalendarRemoteLoadedForUser: (state, getters) => ({user, start, end}) => {
if (!getters.hasUserData(user)) {
return false;
}
for (let interval of getters.getUserData(user).remotesLoaded) {
if (start >= interval.start && end <= interval.end) {
return true;
}
}
return false;
},
/** /**
* return true if the user ranges are shown on calendar * return true if the user ranges are shown on calendar
* *
@ -142,7 +179,7 @@ export default {
return false; return false;
} }
return k.remote; return k.remotes;
}, },

View File

@ -54,7 +54,7 @@ whoami().then(me => {
}); });
if (null !== store.getters.getMainUser) { if (null !== store.getters.getMainUser) {
store.commit('showUserOnCalendar', {ranges: true, remote: true, user: store.getters.getMainUser}); store.commit('showUserOnCalendar', {ranges: true, remotes: true, user: store.getters.getMainUser});
} }
export default store; export default store;

View File

@ -1,4 +1,8 @@
import {createUserData, calendarRangeToFullCalendarEvent} from './utils'; import {
createUserData,
calendarRangeToFullCalendarEvent,
remoteToFullCalendarEvent,
} from './utils';
export default { export default {
setWhoAmiI(state, me) { setWhoAmiI(state, me) {
@ -8,7 +12,7 @@ export default {
state.currentView.start = start; state.currentView.start = start;
state.currentView.end = end; state.currentView.end = end;
}, },
showUserOnCalendar(state, {user, ranges, remote}) { showUserOnCalendar(state, {user, ranges, remotes}) {
if (!state.usersData.has(user.id)) { if (!state.usersData.has(user.id)) {
state.usersData.set(user.id, createUserData(user, state.usersData.size)); state.usersData.set(user.id, createUserData(user, state.usersData.size));
} }
@ -19,7 +23,7 @@ export default {
user.id, user.id,
{ {
ranges: typeof ranges !== 'undefined' ? ranges : cur.ranges, ranges: typeof ranges !== 'undefined' ? ranges : cur.ranges,
remote: typeof remote !== 'undefined' ? remote : cur.remote, remotes: typeof remotes !== 'undefined' ? remotes : cur.remotes,
} }
); );
}, },
@ -85,6 +89,27 @@ export default {
userData.calendarRanges = userData.calendarRanges.concat(eventRanges); userData.calendarRanges = userData.calendarRanges.concat(eventRanges);
userData.calendarRangesLoaded.push({start, end}); userData.calendarRangesLoaded.push({start, end});
}, },
addCalendarRemotesForUser(state, {user, remotes, start, end}) {
let userData;
if (state.usersData.has(user.id)) {
userData = state.usersData.get(user.id);
} else {
userData = createUserData(user, state.usersData.size);
state.usersData.set(user.id, userData);
}
const eventRemotes = remotes
.filter(r => !state.existingEvents.has(`remote_${r.id}`))
.map(r => {
// add to existing ids
state.existingEvents.add(`remote_${r.id}`);
return r;
})
.map(r => remoteToFullCalendarEvent(r));
userData.remotes = userData.remotes.concat(eventRemotes);
userData.remotesLoaded.push({start, end});
},
/* /*
// Calendar // Calendar
setEvents(state, payload) { setEvents(state, payload) {

View File

@ -29,6 +29,8 @@ const createUserData = (user, colorIndex) => {
user: user, user: user,
calendarRanges: [], calendarRanges: [],
calendarRangesLoaded: [], calendarRangesLoaded: [],
remotes: [],
remotesLoaded: [],
mainColor: COLORS[colorId], mainColor: COLORS[colorId],
} }
} }
@ -44,10 +46,21 @@ const calendarRangeToFullCalendarEvent = (entity) => {
}; };
} }
const remoteToFullCalendarEvent = (entity) => {
return {
id: `range_${entity.id}`,
title: entity.title,
start: entity.startDate.datetime8601,
end: entity.endDate.datetime8601,
allDay: false,
};
}
export { export {
addIdToValue, addIdToValue,
calendarRangeToFullCalendarEvent, calendarRangeToFullCalendarEvent,
removeIdFromValue, removeIdFromValue,
remoteToFullCalendarEvent,
mapEntity, mapEntity,
createUserData, createUserData,
}; };