Projet

Général

Profil

Feature #8017

Nouvel agenda personnel

Ajouté par Miguel Moquillon il y a presque 3 ans. Mis à jour il y a plus d'un an.

Statut:
Closed
Priorité:
Normal
Assigné à:
-
Catégorie:
Agenda personnel
Début:
10/06/2016
Echéance:
% réalisé:

100%

Temps estimé:

Description

Fonctionnellement, l'objectif de cette évolution est de proposer un tout nouvel agenda personnel aux utilisateurs.
Techniquement, l'objectif est de centraliser la gestion des événements calendaires et des agendas dans une nouvelle API

Actuellement, chaque application dans Silverpeas qui gère ou utilise un agenda pour placer des événements dans le temps a son propre modèle métier d'un agenda et de la gestion des événements.
L'idée ici est de définir une API et un moteur central d'un tel modèle à destination des applications en vue :
  • d'éviter la duplication de code et surtout la redondance de modèle métier,
  • de permettre le partage d'information (ici les événements) entre applications, par exemple entre les agendas personnels et les almanachs.

Une fois l'API et le moteur en place dans Silverpeas Core, il s'agira alors de remplacer par celui-ci les modèles particuliers de chaque application ; ceci fera toutefois l'objet d'une nouvelle feature dans Silverpeas Components. Néanmoins, un premier jet sera de déléguer la gestion des agendas personnels au nouveau moteur (et d'en profiter pour moderniser l'interface Web de ceux-ci). Celui-ci permettra de valider le moteur.

En vue de la feature #1442, un premier jet a été fait de créer un modèle d'événements transverse. Il s'agira ici de partir de ce premier jet pour l'étendre et définir notre moteur transverse de gestion des agendas.


Demandes liées

Lié à Almanach - Feature #5083: Importer au format iCalClosed07/11/2013

Actions
Lié à Almanach - Feature #6089: Fichiers joints dans l'export iCalNew02/12/2014

Actions

Historique

#1

Mis à jour par Nicolas Eysseric il y a presque 3 ans

#2

Mis à jour par Miguel Moquillon il y a plus de 2 ans

  • Statut changé de New à In progress...
#3

Mis à jour par Miguel Moquillon il y a plus de 2 ans

  • Statut changé de In progress... à Resolved

Le projet a été fusionné dans master de Silverpeas-Core et Silverpeas-Components.
L'API et le moteur qui le motorise définit, comme composant calendaire, uniquement les événements.

Pour créer un agenda :

Calendar myCalendar = new Calendar(componentInstanceId);
mycalendar.setTitle("a title to this calendar");
mycalendar.save();

L'ensemble des agendas d'une instance de composant dans Silverpeas peuvent être récupérés comme suit :

List<Calendar> myCalendars = Calendar.getByComponentInstanceId(componentInstanceId);

et un agenda donné peut-être récupéré par son identifiant unique :

Calendar myCalendar = Calendar.getById(aCalendarId);

Un événement non récurrent est planifié de la façon suivante :

Calendar myCalendar = Calendar.getById(aCalandarId);
CalendarEvent event = CalendarEvent.on(Period.between(today, dayAfterTomorrow))
        .inLocation(aLocation)
        .createdBy(aUserId)
        .withAttendee(aUser)
        .withAttendee("james.bond@007.uk")
        .withTitle(aTitle)
        .withDescription(aShortDescription)
        .withPriority(Priority.HIGH)
        .withVisibilityLevel(VisibilityLevel.PRIVATE)
        .withCategories("Professionnal", "conference")
        .withAttribute("projectId", "234-23")
        .planOn(myCalendar);

ou encore, pour un événement récurrent :

Calendar myCalendar = Calendar.getById(aCalandarId);
CalendarEvent event = CalendarEvent.on(today)
        .inLocation(aLocation)
        .createdBy(aUserId)
        .withTitle(aTitle)
        .withDescription(aShortDescription)
        .recur(Recurrence.every(2, WEEK).until(now.plusWeeks(8)))
        .planOn(myCalendar);

Par défaut, un événement planifié a une priorité normale et une visibilité public. De plus, chaque participant ajouté ont un statut de présence requis et démarre avec un statut de participation en attente de réponse.

On peut aussi ajouter des participants avec un statut de présence plus fin :


Optional<CalendarEvent> maybeAnevent = Calendar.getById(aCalendarId).event(anEventId);
if (maybeAnEvent.isPresent()) {
  maybeAnEvent.get().getAttendees().add(aUser).withPresenceStatus(PresenceStatus.Optional))
}

Ici, le participant est un utilisateur de Silverpeas et sa présence est optionnelle. Un participant ajouté démarre toujours avec un statut de participation en attente de réponse (valeur ParticipationStatus.AWAITING).

Pour faire évoluer la participation, il suffit alors d'utiliser une des méthodes de Attendee ci-dessous:

Optional<CalendarEvent> maybeAnEvent = Calendar.getById(aCalendarId).event(anEventId);
if (maybeAnEvent.isPresent()) {
  CalendarEvent event = maybeAnEvent.get();
  Optional<Attendee> maybeAnAttendee = event.getAttendees().get(aUserId);

  if (maybeAnAttendee.isPresent()) {
    // accept to participate in the event
    anAttendee.accept();

    // decline to participate in the event
    anAttendee.decline();

    // he tentatively accept to participate in the event
    anAttendee.tentativelyAccept();

    // he delegate its attendance to another user
    anAttendee.delegateTo(anotherUser);

    // then update the event with the change
    event.update();
  }
}

Lorsqu'un participant délègue sa participation à un autre utilisateur (externe ou interne à Silverpeas), celui-ci est alors rajouté comme participant à l'événement avec le statut de participation à ParticipationStatut.AWAITING et comme délégué le participant qui a délégué sa participation. Le délégué quant à lui voit son statut de participation passer à ParticipationStatut.DELEGATED et a comme délégué celui à qui il a délégué sa participation. Le délégué peut être accédé via la méthode getDeletaged() de l'Attendee.

Chaque fois qu'une modification est opérée sur un événement, que ce soit dans ses propriétés ou dans ses participants, un appel explicite à la méthode update() est requis afin que les changements soient reportés dans l'agenda. Quand un événement est planifié, mis à jour ou lorsqu'il est supprimé, les participants alors sont notifiés.

A chaque fois qu'un participant est ajouté, enlevé ou que son statut de présence a changé, une notification est envoyée à l'utilisateur concerné. Lorsque le statut de participation est mis à jour, l'ensemble des participants à l'événement en sont notifiés. Par défaut, ce sont les templates présents dans SILVERPEAS_HOME/resources/StringTemplate/core/calendar qui sont utilisés pour formater le message de notification. Toutefois, ces modèles peuvent être surchargés par composant : il suffit alors de définir un template de même nom dans le dossier des templates du composant (SILVERPEAS_HOME/resources/StringTemplate/components/<le composant>/).

En général, lorsque l'on affiche un agenda, on affiche les occurrences des événements. Pour obtenir les occurrences des événements d'un agenda dans le mois de Mai pas exemple :

Calendar calendar = Calendar.getById(aCalendarId);
List<CalendarEventOccurrence> occurrences =
        calendar.in(YearMonth.of(2016, Month.MAY))
            .getEventOccurrences();

ou encore entre deux dates :

Calendar calendar = Calendar.getById(aCalendarId);
List<CalendarEventOccurrence> occurrences =
        calendar.between(LocalDate.of(2016, 1, 23), LocalDate.of(2016, 2, 27))
            .getEventOccurrences();

A partir d'une occurrence, on peut modifier celle-ci en la déplaçant dans le temps ou encore la supprimer :


myOccurrence.setDay(LocalDate.of(2016, 2, 2));
myOccurrence.update();
...
myAnotherOccurrence.delete();

Si l'occurrence est la seule d'un événement, alors l'événement est lui même modifié ou supprimé. Sinon, c'est l'occurrence elle même. Dans le cas d'une mise à jour, ceci conduit à persister les modifications de l'occurrence en base de données. Lorsque l'occurrence sera à nouveau demandé, son état sera donc celui qui aura été persisté tandis que l'état des autres occurrences, non modifiées, sera celui de l'événement (hormis bien sûr la date qui est propre à chaque occurrence). Dans le cas d'une suppression, une exception dans la récurrence de l'événement est ajoutée.

De même, à partir d'une occurrence, il est possible de modifier ou de supprimer toutes les occurrences du même événement en commençant par celle-ci même :


aGivenOccurrence.setDay(LocalDate.of(2016, 2, 2));
aGivenOccurrence.getAttendees().add("toto@chez-les-papoos.net");
CalendarEvent myEvent = aGivenOccurrence.getEvent();
myEvent.updateSince(aGivenOccurrence);
...
myEvent.deleteSince(anAnotherOccurrence);

Ceci peut aussi se faire directement avec l'occurrence :


aGivenOccurrence.setDay(LocalDate.of(2016, 2, 2));
aGivenOccurrence.getAttendees().add("toto@chez-les-papoos.net");
aGivenOccurrence.updateSinceMe();
...
anAnotherOccurrence.deleteSinceMe();

Il est aussi possible de récupérer les occurrences des événements sur une fenêtre de temps pour tous les agendas existant dans le système :

List<CalendarEventOccurrence> occurrences =
        Calendar.getTimeWindowBetween(LocalDate.of(2016, 1, 23), LocalDate.of(2016, 2, 27))
            .getEventOccurrences();

ou encore de filtrer les occurrences à retourner selon un ou plusieurs critères. Par exemple, obtenir les occurrences des événements planifiés sur plusieurs agendas :

List<CalendarEventOccurrence> occurrences =
        Calendar.getTimeWindowBetween(LocalDate.of(2016, 1, 1), LocalDate.of(2016, 1, 8))
            .filter(f -> f.onCalendar(Calendar.getById(calendarId1), Calendar.getById(calendarId2)))
            .getEventOccurrences();

Autre exemple, obtenir les occurrences des événements auquel participent certains utilisateurs de Silverpeas :

List<CalendarEventOccurrence> occurrences =
        Calendar.getTimeWindowBetween(LocalDate.of(2016, 1, 1), LocalDate.of(2016, 1, 8))
            .filter(f -> f.onParticipants(User.getById("0"), User.getById("1"), User.getById("2")))
            .getEventOccurrences();

Les filtres peuvent évidemment être combinés pour restreindre les occurrences à retourner dans une fenêtre de temps donnée.

A côté de ça, il peut être intéressant de traiter les occurrences des événements ou de les grouper selon certaines propriétés. C'est ici qu'intervient alors le concept de vue dans le moteur d'agenda. Une vue est une représentation des occurrences d'événement selon une ou plusieurs propriétés. Actuellement, une seule vue est définie : CalendarEventParticipationView qui permet de grouper les occurrences d'événements par participants (auteur ou invité). Une telle vue peut être créée à partir d'une liste d'occurrences comme suit :

Map<String, List<CalendarEventOccurrence>> byParticipants = 
        new CalendarEventParticipationView().apply(someOccurrences);

#4

Mis à jour par Miguel Moquillon il y a plus de 2 ans

  • Statut changé de Resolved à Closed

Le code a été intégré dans la branche master de Silverpeas-Core et Silverpeas-Components.

#5

Mis à jour par Miguel Moquillon il y a environ 2 ans

  • Lié à Feature #6089: Fichiers joints dans l'export iCal ajouté
#6

Mis à jour par Yohann Chastagnier il y a plus d'un an

  • Statut changé de Closed à Resolved
  • % réalisé changé de 0 à 100

Mes agendas ont été ajoutés à l'espace personnel d'un utilisateur.

ATTENTION :
Lors d'une première intégration de la feature, des scripts SQL ont été créés. De ce fait, tous les serveurs Silverpeas V6 actuels ont les tables créées par ces derniers dans leur base de données.
Comme les agendas des utilisateurs font partie du même "package" que le moteur lui même, et de part la complexité des modifications SQL réalisées depuis la première intégration, nous avons souhaités que la version des scripts reste inchangées. Les tables qui ont été créées pour les agendas doivent donc toutes être supprimées.
Pour ce faire, il faut être muni d'une version de l'installeur Silverpeas postérieure ou égale à la date du 27/04/2017 et réaliser l'enchaînement suivant :
  • modifier le config.properties pour ajouter le couple DEV_CLEANUP_CALENDAR = true
  • lancer silverpeas clean install (avec start pour les déglingos)
  • supprimer du config.properties le fameux paramètre

L'ancien agenda n'a pour le moment pas été violenté.
Cela viendra dans le temps quand nous serons certains que les données manipulées par ce dernier n'ont plus aucun intérêt.
Il faut cependant dans les looks enlever l'entrée de l'espace personnel.


PRs:
#7

Mis à jour par Nicolas Eysseric il y a plus d'un an

  • Sujet changé de Centraliser la gestion des événements calendaires et des agendas dans une nouvelle API à Nouvel agenda personnel
  • Description mis à jour (diff)
  • Catégorie mis à Agenda personnel
  • Statut changé de Resolved à Closed

Validé et intégré !

#8

Mis à jour par David Lesimple il y a plus d'un an

  • Statut changé de Closed à Re-opened

Il y a une erreur lors de l'étape migration, sur les scripts SQL de MSSQL Server:

2 scripts posent problème :
1) \mssql\busCore\up036\update_table.sql :
L'alter table et l'update table ne passent pas lorsqu'il sont dans la même transaction..

2) \mssql\calendar\001\create-table.sql

Dans CREATE TABLE SB_Cal_Components (
  id             VARCHAR(40)   NOT NULL,
  calendarId     VARCHAR(40)   NOT NULL,
  inDays         BIT           NOT NULL,
  startDate      DATETIME      NOT NULL,
  endDate        DATETIME      NOT NULL,
  title          VARCHAR(2000) NOT NULL,
  description    VARCHAR(6000) NOT NULL,
  location       VARCHAR(255)  NULL,
  attributes     VARCHAR(40)   NULL,
  priority       INTEGER       NOT NULL,
  sequence       BIGINT        NOT NULL DEFAULT 0,
  createDate     TIMESTAMP     NOT NULL,
  createdBy      VARCHAR(40)   NOT NULL,
  lastUpdateDate TIMESTAMP     NOT NULL,
  lastUpdatedBy  VARCHAR(40)   NOT NULL,
  version        BIGINT        NOT NULL,
  CONSTRAINT PK_CalComponent PRIMARY KEY (id),
  CONSTRAINT FK_Calendar     FOREIGN KEY (calendarId) REFERENCES SB_Cal_Calendar(id)
);

il ne peut y avoir 2 colonnes avec le type timestamp, d'ailleurs ce type est obsolète sous MSSQL il faut utiliser DATETIME.

#9

Mis à jour par Miguel Moquillon il y a plus d'un an

  • Statut changé de Re-opened à Resolved
Les deux problèmes avec MS-SQL Server ont été résolus :
  • les champs TIMESTAMP ont été convertis en DATETIME dans la table SB_Cal_Components,
  • la mise à jour de la table Personalization fonctionne correctement désormais. Pour ce faire, l'instruction de valorisation de la nouvelle colonne zoneId pour chaque tuple existant dans la table est prise en charge par l'instruction EXEC, propre à MS-SQL Server.
#10

Mis à jour par Miguel Moquillon il y a plus d'un an

  • Statut changé de Resolved à Closed

Formats disponibles : Atom PDF