diff --git a/documentation/database/patches/patch-15.sql b/documentation/database/patches/patch-15.sql new file mode 100644 index 0000000..0689bb9 --- /dev/null +++ b/documentation/database/patches/patch-15.sql @@ -0,0 +1,4 @@ +ALTER TABLE `{$prefix}room` ADD COLUMN `room_playerurl` VARCHAR(254) AFTER `room_name`; +ALTER TABLE `{$prefix}room` ADD COLUMN `room_meetingurl` VARCHAR(254) AFTER `room_playerurl`; +ALTER TABLE `{$prefix}conference` ADD COLUMN `conference_langs` VARCHAR(64) AFTER `conference_events_url`; +ALTER TABLE `{$prefix}conference` ADD COLUMN `conference_rooms_url` VARCHAR(512) AFTER `conference_events_url`; diff --git a/includes/class-Conference.php b/includes/class-Conference.php index ca49131..21968df 100644 --- a/includes/class-Conference.php +++ b/includes/class-Conference.php @@ -1,401 +1,448 @@ . // permalink Conference // %1$d: Conference ID // %2$s: Conference UID define_default( 'PERMALINK_CONFERENCE', '%2$s' ); trait ConferenceTrait { /** * Get conference ID * * @return int */ public function getConferenceID() { return $this->nonnull( Conference::ID ); } /** * Get conference UID * * @return string */ function getConferenceUID() { return $this->get( Conference::UID ); } /** * Get the Conference home (if any) * * Do not confuse with self#getConferenceURL() that you should use instead. * * @return string */ public function getConferenceHome() { return $this->get( Conference::HOME ); } /** * Get localized conference title * * @return string */ public function getConferenceTitle() { return __( $this->get( Conference::TITLE ) ); } /** * Get the Conference Acronym * * @return string */ public function getConferenceAcronym() { return $this->get( Conference::ACRONYM ); } /** * Get the Conference URL * * @param boolean $absolute Set to true to force an absolute URL * @return string */ public function getConferenceURL( $absolute = false ) { $url = null; // check if the home URL is known $custom_home = $this->getConferenceHome(); if( $custom_home ) { // use the known home URL $url = $custom_home; } else { // generate the home URL $url = sprintf( PERMALINK_CONFERENCE, $this->getConferenceID(), $this->getConferenceUID() ); } // normalize this URL to our needs $url = site_page( $url, $absolute ); // eventually append the i18n query string if( $this->hasConferenceI18nSupport() ) { $url = keep_url_in_language( $url ); } return $url; } /** * Get the Conference edit URL * * @param boolean $absolute Set to true to prefere an absolute URL * @return string */ public function getConferenceEditURL() { // query string $args = [ 'id' => $this->getConferenceID(), ]; return Conference::editURL( $args, $absolute ); } /** * Check if the Conference has URLs for every Event * * @return boolean */ public function hasConferenceEventsURL() { - return $this->has( 'conference_events_url' ); + return $this->has( Conference::EVENTS_URL ); } /** * Get the Conference Events URL format * * @return string */ public function getConferenceEventsURLFormat() { return $this->get( Conference::EVENTS_URL ); } + /** + * Check if the Conference has custom URLs for Rooms + * + * @return boolean + */ + public function hasConferenceRoomsURL() { + return $this->has( Conference::EVENTS_URL ); + } + + /** + * Get the Conference Rooms URL format + * + * @return string + */ + public function getConferenceRoomsURLFormat() { + return $this->get( Conference::ROOMS_URL ); + } + function getConferenceHumanStart() { return HumanTime::diff( $this->getConferenceStart() ); } function getConferenceHumanEnd() { return HumanTime::diff( $this->getConferenceEnd() ); } /** * Get the Conference date start * * @param string $format If specified, return the formatted date * @return DateTime|string */ public function getConferenceStart( $format = null ) { $date = $this->get( 'conference_start' ); if( $format ) { return $date->format( $format ); } return $date; } + /** + * Check if the Conference supports some languages + * + * @return boolean + */ + public function hasConferenceLanguages() { + return $this->has( Conference::LANGS ); + } + + /** + * Check if the Conference supports some languages + * + * @return array + */ + public function getConferenceLanguages() { + return explode( ',', $this->get( Conference::LANGS ) ); + } + /** * Check if this Conference has the internationalization support * * @return boolean */ public function hasConferenceI18nSupport() { - return $this->hasConferenceEventsURL(); + return $this->hasConferenceEventsURL() && $this->hasConferenceLanguages(); } /** * Get the Conference date end * * @param string $format If specified, return the formatted date */ public function getConferenceEnd( $format = null ) { $date = $this->get( 'conference_end' ); if( $format ) { return $date->format( $format ); } return $date; } /** * Get URL to trop-iCal API for this conference * * @param boolean $absolute Set to true for an absolute URL * @return string */ function getConferenceCalURL( $absolute = false ) { $conf = urlencode( $this->getConferenceUID() ); return site_page( "api/tropical.php?conference=$conf", $absolute ); } /** * Get localized conference description * * @return string */ public function getConferenceDescription() { return nl2br( __( $this->get( Conference::DESCRIPTION ) ) ); } /** * Get localized conference quote * * @return string */ public function getConferenceQuote() { return nl2br( __( $this->get( 'conference_quote' ) ) ); } /** * Get localized conference subtitle * * @return string */ public function getConferenceSubtitle() { return __( $this->get( Conference::SUBTITLE ) ); } /** * Factory a FullEvent by this conference * * @return Query */ public function factoryFullEventByConference() { return FullEvent::factoryByConference( $this->getConferenceID() ); } /** * Get the URL to create an Event in this Conference * * @param boolean $absolute Flag to have an absolute URL * @return string */ public function getURLToCreateEventInConference( $args = [], $absolute = false ) { $args['conference'] = $this->getConferenceUID(); return FullEvent::editURL( $args, $absolute ); } /** * Check if this Conference is editable by me */ public function isConferenceEditable() { return has_permission( 'edit-conferences' ); } /** * Normalize a Conference object */ protected function normalizeConference() { $this->integers( Conference::ID, Conference::DAYS, Location::ID ); $this->datetimes( Conference::START, Conference::END ); } } /** * A Conference is an event in a certain Location */ class Conference extends Queried { use ConferenceTrait; /** * Database table name */ const T = 'conference'; /** * Conference ID column */ const ID = 'conference_ID'; /** * Conference UID column */ const UID = 'conference_uid'; /** * Conference home URL */ const HOME = 'conference_home'; /** * Conference title column */ const TITLE = 'conference_title'; /** * Description column name */ const DESCRIPTION = 'conference_description'; /** * Subtitle column name */ const SUBTITLE = 'conference_subtitle'; /** * Start column name */ const START = 'conference_start'; /** * End column name */ const END = 'conference_end'; + /** + * Conference languages + */ + const LANGS = 'conference_langs'; + /** * Acronym column name */ const ACRONYM = 'conference_acronym'; /** * Persons URL column name */ const PERSONS_URL = 'conference_persons_url'; /** * Events URL column name */ const EVENTS_URL = 'conference_events_url'; + /** + * Events URL column name + */ + const ROOMS_URL = 'conference_rooms_url'; + /** * Days column name */ const DAYS = 'conference_days'; /** * Complete ID column name */ const ID_ = self::T . DOT . self::ID; /** * Complete Location ID column name */ const LOCATION_ = self::T . DOT . Location::ID; /** * Maximum UID length * * @override */ const MAXLEN_UID = 32; /** * Constructor */ public function __construct() { $this->normalizeConference(); } /** * Build the conference edit URL * * @param array $args Query string arguments * @param boolean $absolute Flag to prefere an absolute URL * @return string */ public static function editURL( $args = [], $absolute = false ) { // build the base URL $url = site_page( ADMIN_BASE_URL . '/conference.php', $absolute ); // append the query string return http_build_get_query( $url, $args ); } /** * All the public fields of a Conference * * @return array */ public static function fields() { return [ self::ID_, self::TITLE, self::UID, self::TITLE, self::SUBTITLE, self::DESCRIPTION, self::START, self::END, self::ACRONYM, self::PERSONS_URL, self::EVENTS_URL, self::DAYS, + self::LANGS, ]; } } diff --git a/includes/class-FullEvent.php b/includes/class-FullEvent.php index 915b790..bdf8abd 100644 --- a/includes/class-FullEvent.php +++ b/includes/class-FullEvent.php @@ -1,217 +1,237 @@ . class_exists('Conference'); class_exists('Location'); class_exists('Room'); class_exists('Chapter'); class_exists('Track'); trait FullEventTrait { + public function hasEventStandardURL() { + return $this->has( Conference::UID ) && + $this->has( Event ::UID ) && + $this->has( Chapter ::UID ); + } + /** * Check if the Event has a permalink * * @return bool */ public function hasEventPermalink() { + return $this->hasEventExternalURL() || $this->hasEventStandardURL(); + } - // if is an external URL, is easy-peasy - if( $this->hasEventExternalURL() ) { - return true; - } - - return $this->has( Conference::UID ) && - $this->has( Event ::UID ) && - $this->has( Chapter ::UID ); + /** + * Get the Event standard URL + * + * The standard URL is the opposite of the external URL. + * + * @param boolean $absolute + * @return string + */ + public function getEventStandardURL( $absolute = null ) { + return FullEvent::permalink( + $this->getConferenceUID(), + $this->getEventUID(), + $this->getChapterUID(), + $absolute, + $this->getConferenceEventsURLFormat(), + $this->hasConferenceI18nSupport() + ); } /** * Get the Event URL * * @param boolean $absolute Set to true to force an absolute URL * @return string */ public function getEventURL( $absolute = false ) { + if( $this->hasEventStandardURL() ) { + return $this->getEventStandardURL( $absolute ); + } + // is this is an external Event, is easy-peasy if( $this->hasEventExternalURL() ) { return $this->getEventExternalURL(); } - return FullEvent::permalink( - $this->getConferenceUID(), - $this->getEventUID(), - $this->getChapterUID(), - $absolute, - $this->getConferenceEventsURLFormat() - ); + return '#'; } /** * Create a Query to find the next Event in the same Room * * @return Query */ public function factoryNextFullEvent() { $date = $this->getEventEnd( 'Y-m-d H:i:s' ); return $this->factoryFullEventInSameContext() ->whereStr( 'event_start', $date, '>=' ) ->orderBy( 'event_start', 'ASC' ); } /** * Create a Query to find the previous Event in the same Room * * @return Query */ public function factoryPreviousFullEvent( $compare = '<=' ) { $date = $this->getEventStart( 'Y-m-d H:i:s' ); return $this->factoryFullEventInSameContext() ->whereStr( 'event_end', $date, '<=' ) ->orderBy( 'event_end', 'DESC' ); } /** * Get the edit URL for this FullEvent * * @deprecated * @param boolean $absolute Flag to require an absolute URL * @return string */ public function getFullEventEditURL( $absolute = false ) { return $this->getEventEditURL( $absolute ); } private function factoryFullEventInSameContext() { return FullEvent::factory() ->whereInt( 'event.conference_ID', $this->getConferenceID() ) ->whereInt( 'event.room_ID', $this->getRoomID() ); } } /** * An Event with all the bells and whistles */ class FullEvent extends Event { use FullEventTrait; use ConferenceTrait; use LocationTrait; use ChapterTrait; use RoomTrait; use TrackTrait; public function __construct() { $this->normalizeEvent(); $this->normalizeConference(); $this->normalizeChapter(); $this->normalizeRoom(); $this->normalizeTrack(); } /** * Query constructor * * @return Query */ public static function factory() { return ( new QueryEvent() ) ->select( Conference::fields() ) ->select( Event ::fields() ) ->select( Track ::fields() ) ->select( Chapter ::fields() ) ->select( Room ::fields() ) ->joinConference() ->joinTrackChapterRoom() ->defaultClass( __CLASS__ ); } static function factoryByConference( $conference_ID ) { return self::factory() ->whereInt( Event::CONFERENCE_, $conference_ID ); } /** * @deprecate Use self::factoryFromConferenceAndUID() instead */ static function factoryByConferenceAndUID( $conference_ID, $event_uid ) { $event_uid = Event::sanitizeUID( $event_uid ); return self::factoryByConference( $conference_ID ) ->whereStr( Event::UID, $event_uid ); } /** * Factory from a Conference object and the Event UID * * @param object $conference * @param string $event_uid * @return Query */ public static function factoryFromConferenceAndEventUID( $conference, $event_uid ) { $event_uid = Event::sanitizeUID( $event_uid ); $conference_ID = $conference->getConferenceID(); return self::factoryByConference( $conference_ID ) ->whereStr( Event::UID, $event_uid ); } static function queryByConferenceAndUID( $conference_ID, $event_uid ) { return self::factoryByConferenceAndUID( $conference_ID, $event_uid ) ->queryRow(); } static function factoryByUser( $user_ID ) { return self::factory() ->from( EventUser::T ) ->equals( EventUser::EVENT_, Event::ID_ ) ->whereInt( EventUser::USER_, $user_ID ) ->orderBy( EventUser::ORDER ); } static function factoryByConferenceChapter( $conference_ID, $chapter_ID ) { return self::factoryByConference( $conference_ID ) ->whereInt( Event::CHAPTER_, $chapter_ID ); } /** * Get an absolute FullEvent permalink * * @param $conference_uid string Conference UID * @param $event_uid string Event UID * @param $chapter_uid string Chapter UID * @param $absolute string Force an absolute URL * @param $format string Permalink in printf format. Arguments: 1 Conference UID, 2 Event UID, 3 Chapter UID + * @param $jass_i18n_support Check if the Conference has I18n support * @return string */ - public static function permalink( $conference_uid, $event_uid, $chapter_uid, $absolute = false, $format = null ) { + public static function permalink( $conference_uid, $event_uid, $chapter_uid, $absolute = false, $format = null, $has_i18n_support = true ) { // eventually take a default format if( !$format ) { $format = PERMALINK_EVENT; } // make the permalink $url = sprintf( $format, $conference_uid, $event_uid, $chapter_uid ); // adapt the URL for our needs $url = site_page( $url, $absolute ); // eventually append I18N query string - return keep_url_in_language( $url ); + if( $has_i18n_support ) { + $url = keep_url_in_language( $url ); + } + + return $url; } } diff --git a/includes/class-Room.php b/includes/class-Room.php index 619f9e1..34db7a1 100644 --- a/includes/class-Room.php +++ b/includes/class-Room.php @@ -1,108 +1,188 @@ . +/** + * Default room permalink: + * + * room/something + * + * Placeholders: + * %1$d: Room ID + * %1$s: Room UID + */ +define_default( 'ROOM_PERMALINK', 'room/%2$s' ); + +/** + * Methods related to a Room class + */ trait RoomTrait { /** * Get room ID * * @return int */ public function getRoomID() { return $this->get( Room::ID ); } /** * Get room UID * * @return string */ public function getRoomUID() { return $this->get( Room::UID ); } + /** + * Get the Room URL + * + * @return string + */ + public function getRoomURL( $absolute = false ) { + $url = sprintf( + // TODO: eventually inherit this from the Conference + ROOM_PERMALINK, + $this->getRoomID(), + $this->getRoomUID() + ); + return site_page( $url, $absolute ); + } + /** * Get localized room name * * @return string */ public function getRoomName() { return __( $this->get( ROOM::NAME ) ); } + /** + * Get the Room URL (if any) + * + * @return string + */ + public function getRoomPlayerURL() { + return $this->get( Room::PLAYER_URL ); + } + + /** + * Get the Room chat resource (whatever it is) + * + * @return string + */ + public function getRoomChatURL() { + return $this->get( Room::CHAT_URL ); + } + + /** + * Check if the Room has a chat meeting URL + * + * @return boolean + */ + public function hasRoomMeetingURL() { + return $this->has( Room::MEETING_URL ); + } + + /** + * Get the Room meeting URL + * + * @return string + */ + public function getRoomMeetingURL() { + return $this->get( Room::MEETING_URL ); + } + /** * Normalize a Room object */ protected function normalizeRoom() { $this->integers( Room::ID ); } } /** * A Room host Talks and it's in a Location */ class Room extends Queried { use RoomTrait; /** * Database table name */ const T = 'room'; /** * Maximum UID length * * @override Queried::MAXLEN_UID */ const MAXLEN_UID = 64; /** * Room ID column */ const ID = 'room_ID'; /** * Room UID column */ const UID = 'room_uid'; /** * Room name column */ const NAME = 'room_name'; + /** + * Room player URL column name + */ + const PLAYER_URL = 'room_playerurl'; + + /** + * Room chat column name + */ + const CHAT_URL = 'room_chaturl'; + + /** + * Room meeting column name + */ + const MEETING_URL = 'room_meetingurl'; + /** * Complete ID column name */ const ID_ = self::T . DOT . self::ID; /** * Constructor */ public function __construct() { $this->normalizeRoom(); } /** * All the public room fields * * @return string */ public static function fields() { return Room::T . DOT . STAR; } }