Class Utils

java.lang.Object
org.exoplatform.agenda.util.Utils

public class Utils extends Object
  • Field Details

  • Method Details

    • getCalendarOwnersOfUser

      public static List<Long> getCalendarOwnersOfUser(org.exoplatform.social.core.space.spi.SpaceService spaceService, org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.identity.model.Identity userIdentity)
    • addUserSpacesIdentities

      public static void addUserSpacesIdentities(org.exoplatform.social.core.space.spi.SpaceService spaceService, org.exoplatform.social.core.manager.IdentityManager identityManager, String username, List<Long> identityIds) throws Exception
      Throws:
      Exception
    • getOccurrences

      public static List<org.exoplatform.agenda.model.Event> getOccurrences(org.exoplatform.agenda.model.Event event, LocalDate from, LocalDate to, int limit)
    • getOccurrenceId

      public static ZonedDateTime getOccurrenceId(boolean allDay, net.fortuna.ical4j.model.DateTime eventStartDate, ZoneId eventStartDateTimeZone)
    • getOccurrenceId

      public static ZonedDateTime getOccurrenceId(boolean allDay, ZonedDateTime eventStartDate, ZoneId eventStartDateTimeZone)
    • getICalendarRecur

      public static net.fortuna.ical4j.model.Recur getICalendarRecur(org.exoplatform.agenda.model.EventRecurrence recurrence, ZoneId zoneId)
    • checkAclByCalendarOwner

      public static void checkAclByCalendarOwner(org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.space.spi.SpaceService spaceService, long ownerId, String username) throws IllegalAccessException
      Parameters:
      identityManager - IdentityManager service instance
      spaceService - SpaceService service instance
      ownerId - calendar owner Identity technical identifier
      username - name of user accessing calendar data
      Throws:
      IllegalAccessException - when the user ACL fails
    • canCreateEvent

      public static boolean canCreateEvent(org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.space.spi.SpaceService spaceService, long ownerId, long userIdentityId)
      Parameters:
      identityManager - IdentityManager service instance
      spaceService - SpaceService service instance
      ownerId - calendar owner Identity technical identifier
      userIdentityId - Identity identifier of user accessing calendar data
      Returns:
      true if user can create event in a calendar, else return false
    • canInviteeEdit

      public static boolean canInviteeEdit(org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.space.spi.SpaceService spaceService, long ownerId)
      Parameters:
      identityManager - IdentityManager service instance
      spaceService - SpaceService service instance
      ownerId - calendar owner Identity technical identifier
      Returns:
      true if owner is a space and has at least one redactor, else return false
    • canEditCalendar

      public static boolean canEditCalendar(org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.space.spi.SpaceService spaceService, long ownerId, long userIdentityId)
      Parameters:
      identityManager - IdentityManager service instance
      spaceService - SpaceService service instance
      ownerId - calendar owner Identity technical identifier
      userIdentityId - Identity identifier of user accessing calendar data
      Returns:
      true if user can modify calendar or its events, else return false
    • canPublishCalendar

      public static boolean canPublishCalendar(org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.space.spi.SpaceService spaceService, long ownerId, long userIdentityId)
      Whether a user may publish a calendar as a private link, and so read, create, reset or delete that link (EXO-90252).

      A personal calendar: its owner. A space calendar: a real manager of the space — a member holding the manager role, social's isMember(space, user) && isManager(space, user). Deliberately not canEditCalendar(org.exoplatform.social.core.manager.IdentityManager, org.exoplatform.social.core.space.spi.SpaceService, long, long), whose SpaceService.canManageSpace also admits super-managers (platform administrators, holders of the space template's admin permission) who are not managers of that space: a link anyone can read from outside eXo is published by the people who run the space, and only while they do.

      Parameters:
      identityManager - IdentityManager service instance
      spaceService - SpaceService service instance
      ownerId - calendar owner Identity technical identifier
      userIdentityId - Identity identifier of the user
      Returns:
      true when the user may publish the calendar
    • canAccessCalendar

      public static boolean canAccessCalendar(org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.space.spi.SpaceService spaceService, long ownerId, long userIdentityId)
      Parameters:
      identityManager - IdentityManager service instance
      spaceService - SpaceService service instance
      ownerId - calendar owner Identity technical identifier
      userIdentityId - Identity identifier of user accessing calendar data
      Returns:
      true if user can access calendar or its events, else return false
    • broadcastEvent

      public static void broadcastEvent(org.exoplatform.services.listener.ListenerService listenerService, String eventName, Object source, Object data)
    • getIdentityById

      public static org.exoplatform.social.core.identity.model.Identity getIdentityById(org.exoplatform.social.core.manager.IdentityManager identityManager, long identityId)
    • getIdentityById

      public static org.exoplatform.social.core.identity.model.Identity getIdentityById(org.exoplatform.social.core.manager.IdentityManager identityManager, String identityId)
    • getIdentityIdByUsername

      public static long getIdentityIdByUsername(org.exoplatform.social.core.manager.IdentityManager identityManager, String username)
    • getSpaceMembersBySpaceName

      public static List<String> getSpaceMembersBySpaceName(String spaceName, org.exoplatform.social.core.space.spi.SpaceService spaceService)
    • isEventAttendee

      public static boolean isEventAttendee(org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.space.spi.SpaceService spaceService, long identityId, org.exoplatform.agenda.model.EventAttendeeList eventAttendeeList)
    • isEventAttendee

      public static boolean isEventAttendee(org.exoplatform.social.core.manager.IdentityManager identityManager, org.exoplatform.social.core.space.spi.SpaceService spaceService, long identityId, List<org.exoplatform.agenda.model.EventAttendee> eventAttendees)
    • getICalTimeZone

      public static net.fortuna.ical4j.model.TimeZone getICalTimeZone(ZoneId zoneId)
    • toDateTime

      public static ZonedDateTime toDateTime(String dateTimeString, ZoneId userTimeZone)
    • detectEventModifiedFields

      public static void detectEventModifiedFields(org.exoplatform.agenda.model.Event newEvent, org.exoplatform.agenda.model.Event oldEvent, org.exoplatform.agenda.model.AgendaEventModification eventModification)
    • getResourceBundleLabel

      public static String getResourceBundleLabel(Locale locale, String label)
    • buildGuestResponseConfirmationPage

      public static String buildGuestResponseConfirmationPage(org.exoplatform.agenda.constant.EventAttendeeResponse response, Locale locale)
      Builds the minimal HTML page acknowledging an answer given through a tokenised invitation link, naming the answer that was recorded.

      It was introduced for an external attendee - a guest invited by mail address, having no account on the platform - who cannot be redirected to the event page of the portal, which would only display a login form to them (EXO-89705). Since EXO-89753 it serves a second reader with the same problem for a different reason: somebody answering from the description of their calendar copy, on a client which renders no RSVP control of its own. That reader gets no feedback whatsoever from the client they clicked in, so the page has to say what was recorded, not merely that something was - which is why the answer is named in the sentence rather than implied by the page having loaded at all.

      Parameters:
      response - the EventAttendeeResponse that has just been recorded for the attendee
      locale - Locale used to translate the labels of the page, the default Locale of the server is used when null
      Returns:
      the HTML content of the confirmation page
    • buildInvitationExpiredPage

      public static String buildInvitationExpiredPage(Locale locale, String eventUrl)
      Builds the page shown to somebody who follows an invitation link whose meeting is over.

      The alternative was to let the refusal fall through as a bare 401, which tells its reader nothing at all: they clicked an Accept button in an invitation and got a blank error, with no way to tell whether they had answered, whether the link was broken, or whether they were looking at a fault of their own. This is the same self contained surface the confirmation above uses, saying instead that the invitation can no longer be answered here - and carrying a way into eXo, where the meeting can still be looked at and, if it has not happened yet, still be answered.

      The link is offered rather than followed. Redirecting a guest, who has no account, would land them on a login form - the exact outcome EXO-89705 built this page to avoid.

      Parameters:
      locale - Locale used to translate the labels of the page, the default Locale of the server is used when null
      eventUrl - absolute address of the event inside eXo, blank when the portal cannot be asked for one, in which case the page simply carries no link
      Returns:
      the HTML content of the expired invitation page
    • invitationTokenExpiry

      public static long invitationTokenExpiry(org.exoplatform.agenda.model.Event event)
      The instant past which a tokenised invitation link for this event stops being honoured.

      The bound is the meeting itself. A link exists to answer an invitation, and once the meeting is over there is no answer left to give, so nothing legitimate is lost by refusing it - while a link that outlives its meeting stays a usable "answer as this person" credential for anyone the mail was ever forwarded to (EXO-89752).

      Which end. For a recurring event Event.getEnd() is the end of the first occurrence, not of the series - the two are stored in different rows and swapped apart in EntityMapper.fromEntity(org.exoplatform.agenda.entity.EventEntity) - so bounding a series by it would kill the link after its first meeting, while an answer legitimately applies to every occurrence still to come. The series end, EventRecurrence.getOverallEnd(), is used instead.

      A series that never ends is already answered, and not here. EntityMapper stores overallStart.plusYears(10) as the end of an endless recurrence, and reads it back into getOverallEnd(). That is a persisted property of the event rather than a horizon invented in this method, so an endless standup gets ten years of answerable link and this code gains no second opinion about what "no end" means.

      Why there is a grace period at all. Expiring at the exact end would kill the link in the hand of somebody answering during the meeting's last minute, and would kill it outright for an invitation whose meeting was lengthened after the mail went out. A day covers both, plus any clock skew between the node that minted the token and the node that reads it, and is short enough that a leaked link is not a lasting credential.

      It is a pure function of the event, and must stay one. The same value has to come out on every render, because the calendar copy writes these links into its DESCRIPTION and the mirror rewrites any copy whose description changed (EXO-89753, EXO-89716). Deriving the bound from "now" - a sliding window from the moment of minting - would make every sweep mint a different token and put every copy into permanent churn. Nothing in this method may read the clock.

      Parameters:
      event - the Event the invitation answers, null tolerated
      Returns:
      the expiry as a number of seconds since the epoch, or 0 when the event carries no date to bound it by - which the caller must treat as "cannot be answered" rather than as "never expires"
    • getUserLanguage

      public static String getUserLanguage(String userId)
      Gets platform language of user. In case of any errors return null.
      Parameters:
      userId - user Id
      Returns:
      the platform language
    • isExternal

      public static boolean isExternal(String userId)
    • generateIcsFile

      public static byte[] generateIcsFile(String eventId, String ownerId, String eventSummary, String eventDescription, String startDateRFC3339, String endDateRFC3339, String eventConference, String eventModifierId, String eventCreatorFullName, String location, String eventUrl, org.exoplatform.agenda.constant.EventAvailability availability, Locale userLocale, ZoneId timeZone)
      Builds the iCalendar document eXo attaches to the mail that announces an event.

      The document is a PUBLISH one, not a REQUEST: answering an invitation is handled by the tokenised links carried in the mail body, not by iMIP. Method.PUBLISH is written into the body so it says the same thing as the method=PUBLISH parameter the MIME part already declares, as RFC 6047 asks.

      Parameters:
      eventId - identifier of the event, used to derive a UID that is stable across every mail describing this meeting (EXO-89680)
      ownerId - identifier of the identity owning the event's calendar, used to name the space the invitation comes from
      eventSummary - event title, written as SUMMARY
      eventDescription - event description, HTML as the editor stored it
      startDateRFC3339 - event start, RFC 3339
      endDateRFC3339 - event end, RFC 3339
      eventConference - conference URL, blank when the event has none
      eventModifierId - identifier of the identity to write as ORGANIZER
      eventCreatorFullName - display name of whoever sent the invitation
      location - event location, blank when the event has none
      eventUrl - link back to the event in eXo, written as URL and named in the description. Blank for a recipient with no eXo account: the link resolves to a login screen for a guest, so the caller — which is the only party that knows who the mail is going to — leaves it out for one (EXO-89751)
      availability - whether the event takes the recipient's time, written as TRANSP. FREE is transparent, everything else — including DEFAULT and a null — is opaque, the same reading CalendarFeedIcsWriter and the CalDAV writer use. It must be written rather than left out: RFC 5545 §3.8.2.7 makes an absent TRANSP default to OPAQUE, so saying nothing is saying "busy" (EXO-90327)
      userLocale - locale of the recipient, the one the labels are read in
      timeZone - time zone the dates are written in
      Returns:
      the iCalendar document, UTF-8 encoded
    • escapeEmoticons

      public static String escapeEmoticons(String text)
      Replaces every non-ASCII character by its HTML numeric entity, so an emoji survives a mail body that is not read as UTF-8.
      Parameters:
      text - text to escape
      Returns:
      the text with every codepoint above 127 written as an entity