diff --git a/lib/api/attachments.php b/lib/api/attachments.php index 97bfe23..dd7dfd5 100644 --- a/lib/api/attachments.php +++ b/lib/api/attachments.php @@ -1,198 +1,197 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_attachments extends kolab_api { protected $model = 'attachment'; public function run() { $this->initialize_handler(); $path = $this->input->path; $method = $this->input->method; if ($path[0] && $path[1] && $method == 'POST') { $this->api_attachment_create(); } else if ($path[2]) { if ($method == 'GET') { if ($path[3] === 'get') { $this->api_attachment_body(); } else { $this->api_attachment_info(); } } else if ($method == 'PUT') { $this->api_attachment_update(); } else if ($method == 'HEAD') { $this->api_attachment_exists(); } else if ($method == 'DELETE') { $this->api_attachment_delete(); } } throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } /** * Fetch attachment info */ protected function api_attachment_info() { $folder = $this->input->path[0]; $object_uid = $this->input->path[1]; $attach_uid = $this->input->path[2]; $object = $this->backend->object_get($folder, $object_uid); $context = array( 'folder_uid' => $folder, 'object_uid' => $object_uid, 'object' => $object ); // get attachment part from the object $attachment = $this->get_attachment($object, $attach_uid); $this->output->send($attachment, $this->model, $context); } /** * Create a attachment */ protected function api_attachment_create() { $folder = $this->input->path[0]; $object_uid = $this->input->path[1]; $object = $this->backend->object_get($folder, $object_uid); $attachment = $this->input->input('attachment'); $context = array( 'folder_uid' => $folder, 'object_uid' => $object_uid, 'object' => $object ); // @TODO // $uid = $this->backend->attachment_add($folder, $object, $attachment); // $this->output->send(array('uid' => $uid), $this->model, $context, array('uid')); } /** * Update specified attachment */ protected function api_attachment_update() { $folder = $this->input->path[0]; $object_uid = $this->input->path[1]; $object = $this->backend->object_get($folder, $object_uid); $attachment = $this->input->input('attachment'); $context = array( 'folder_uid' => $folder, 'object_uid' => $object_uid, 'object' => $object ); // @TODO // merge old object's data with new properties // $note = $this->merge_data($note, $object); // $this->backend->object_update($folder, $note, 'note'); // $this->output->send(array('id' => $uid), $this->model, $folder); // $this->output->send_status(kolab_api_output::STATUS_EMPTY); } /** * Check if specified attachment exists */ protected function api_attachment_exists() { $folder = $this->input->path[0]; $object_uid = $this->input->path[1]; $attach_uid = $this->input->path[2]; $object = $this->backend->object_get($folder, $object_uid); // get attachment part from the object $attachment = $this->get_attachment($object, $attach_uid); $this->output->send_status(kolab_api_output::STATUS_OK); } /** * Remove specified attachment */ protected function api_attachment_delete() { $folder = $this->input->path[0]; $object_uid = $this->input->path[1]; $attach_uid = $this->input->path[2]; $object = $this->backend->object_get($folder, $object_uid); -// @TODO -// $this->backend->attachment_delete($folder, $object, $attach_uid); + $this->backend->attachment_delete($object, $attach_uid); -// $this->output->send_status(kolab_api_output::STATUS_EMPTY); + $this->output->send_status(kolab_api_output::STATUS_EMPTY); } /** * Fetch attachment body */ protected function api_attachment_body() { $folder = $this->input->path[0]; $object_uid = $this->input->path[1]; $attach_uid = $this->input->path[2]; $object = $this->backend->object_get($folder, $object_uid); // get attachment part from the object $attachment = $this->get_attachment($object, $attach_uid); // @TODO: set headers // print attachment body $this->backend->attachment_get($object, $attach_uid, -1); exit; } /** * Find attachment in an object/message */ protected function get_attachment($object, $id) { if ($object) { $attachments = (array) $this->get_object_attachments($object); foreach ($attachments as $attachment) { if ($attachment->mime_id == $id) { return $attachment; } } } throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } } diff --git a/lib/filter/mapistore.php b/lib/filter/mapistore.php index 500fe7c..39dae0d 100644 --- a/lib/filter/mapistore.php +++ b/lib/filter/mapistore.php @@ -1,585 +1,594 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_filter_mapistore extends kolab_api_filter { protected $input; protected $attrs_filter; // Common properties [MS-OXCMSG] protected static $map = array( // 'PidTagAccess' => '', // 'PidTagAccessLevel' => '', // 0 - read-only, 1 - modify // 'PidTagChangeKey' => '', 'PidTagCreationTime' => 'creation-date', // PtypTime, UTC 'PidTagLastModificationTime' => 'last-modification-date', // PtypTime, UTC // 'PidTagLastModifierName' => '', // 'PidTagObjectType' => '', // @TODO // 'PidTagHasAttachments' => '', // @TODO // 'PidTagRecordKey' => '', // 'PidTagSearchKey' => '', -// 'PidLidCategories' => 'categories', // @TODO + 'PidNameKeywords' => 'categories', ); /** * Modify request path * * @param array (Exploded) request path */ public function path(&$path) { // handle differences between OpenChange API and Kolab API // here we do only very basic modifications, just to be able // to select apprioprate api action class if ($path[0] == 'calendars') { $path[0] = 'events'; } } /** * Executed before every api action * * @param kolab_api_input Request */ public function input(&$input) { $this->input = $input; // handle differences between OpenChange API and Kolab API switch ($input->action) { case 'folders': // in OpenChange folders/1/folders means get all folders if ($input->method == 'GET' && $input->path[0] === '1' && $input->path[1] == 'folders') { $input->path = array(); $type = 'folder'; } // in OpenChange folders/0/folders means get the hierarchy of the NON IPM Subtree // we should ignore/send empty request else if ($input->method == 'GET' && $input->path[0] === '0' && $input->path[1] == 'folders') { // @TODO throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } else if ($input->path[1] == 'messages') { $input->path[1] = 'objects'; if ($input->args['properties']) { $type = $input->api->backend->folder_type($input->path[0]); list($type, ) = explode('.', $type); } } else if ($input->path[1] == 'deletemessages') { $input->path[1] = 'deleteobjects'; } // properties filter, map MAPI attribute names to Kolab attributes if ($type && $input->args['properties']) { $this->attrs_filter = explode(',', $this->input->args['properties']); $properties = $this->attributes_filter($this->attrs_filter, $type); $input->args['properties'] = implode(',', $properties); } break; case 'notes': // Notes do not have attachments in Exchange if ($input->path[1] === 'attachments' || count($this->path) > 2) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } break; } $common_action = !in_array($input->action, array('folders', 'info')); // convert / to // or /// if ($common_action && ($uid = $input->path[0])) { list($folder, $msg, $attach) = self::uid_decode($uid); $path = array($folder, $msg); if ($attach) { $path[] = $attach; } array_splice($input->path, 0, 1, $path); } // convert parent_id into path on object create request if ($input->method == 'POST' && $common_action && !count($input->path)) { $data = $input->input(null, true); if ($data['parent_id']) { $input->path[0] = $data['parent_id']; } else { throw new kolab_api_exception(kolab_api_exception::INVALID_REQUEST); } } } /** * Executed when parsing request body * * @param string Request data * @param string Expected object type * @param string Original object data (set on update requests) */ public function input_body(&$data, $type = null, $original_object = null) { $input = $this->input; // handle differences between OpenChange API and Kolab API // Note: input->path is already modified by input() and path() above switch ($input->action) { case 'folders': // folders//deletemessages input if ($input->path[1] == 'deleteobjects') { // Kolab API expects just a list of identifiers, I.e.: // [{"id": "1"}, {"id": "2"}] => ["1", "2"] foreach ((array) $data as $idx => $element) { $data[$idx] = $element['id']; } } break; } switch ($type) { case 'attachment': case 'event': case 'note': case 'task': case 'contact': case 'mail': case 'folder': $model = $this->get_model_class($type); $data = $model->input($data, $original_object); break; } } /** * Apply filter on output data * * @param array Result data * @param string Object type * @param array Context (folder_uid, object_uid, object) * @param array Optional attributes filter */ public function output(&$result, $type, $context = null, $attrs_filter = array()) { // handle differences between OpenChange API and Kolab API $model = $this->get_model_class($type); if (!empty($this->attrs_filter)) { $attrs_filter = array_combine($this->attrs_filter, $this->attrs_filter); } else if (!empty($attrs_filter)) { $attrs_filter = $this->attributes_filter($attrs_filter, $type, true); $attrs_filter = array_combine($attrs_filter, $attrs_filter); } foreach ($result as $idx => $data) { if ($filtered = $model->output($data, $context)) { // apply properties filter (again) if (!empty($attrs_filter)) { $filtered = array_intersect_key($filtered, $attrs_filter); } $result[$idx] = $filtered; } else { unset($result[$idx]); $unset = true; } } if ($unset) { $result = array_values($result); } } /** * Executed for response headers * * @param array Response headers */ public function headers(&$headers) { // handle differences between OpenChange API and Kolab API foreach ($headers as $name => $value) { switch ($name) { case 'X-Count': $headers['X-mapistore-rowcount'] = $value; unset($headers[$name]); break; } } } /** * Executed for empty response status * * @param int Status code */ public function send_status(&$status) { // handle differences between OpenChange API and Kolab API } /** * Extracts data from kolab data array */ public static function get_kolab_value($data, $name) { $name_items = explode('.', $name); $count = count($name_items); $value = $data[$name_items[0]]; // special handling of x-custom properties if ($name_items[0] === 'x-custom') { foreach ((array) $value as $custom) { if ($custom['identifier'] === $name_items[1]) { return $custom['value']; } } return null; } for ($i = 1; $i < $count; $i++) { if (!is_array($value)) { return null; } list($key, $num) = explode(':', $name_items[$i]); $value = $value[$key]; if ($num !== null && $value !== null) { $value = is_array($value) ? $value[$num] : null; } } return $value; } /** * Sets specified kolab data item */ public static function set_kolab_value(&$data, $name, $value) { $name_items = explode('.', $name); $count = count($name_items); $element = &$data; // x-custom properties if ($name_items[0] === 'x-custom') { // this is supposed to be converted later by parse_common_props() $data[$name] = $value; return; } if ($count > 1) { for ($i = 0; $i < $count - 1; $i++) { $key = $name_items[$i]; if (!array_key_exists($key, $element)) { $element[$key] = array(); } $element = &$element[$key]; } } $element[$name_items[$count - 1]] = $value; } /** * Converts kolab identifiers describind the object into * MAPI identifier that can be easily used in URL. * * @param string Folder UID * @param string Object UID * @param string Optional attachment identifier * * @return string Object identifier */ public static function uid_encode($folder_uid, $msg_uid, $attach_id = null) { $result = array($folder_uid, $msg_uid); if ($attach_id) { $result[] = $attach_id; } $result = array_map(array('kolab_api_filter_mapistore', 'uid_encode_item'), $result); return implode('.', $result); } /** * Converts back the MAPI identifier into kolab folder/object/attachment IDs * * @param string Object identifier * * @return array Object identifiers */ public static function uid_decode($uid) { $result = explode('.', $uid); $result = array_map(array('kolab_api_filter_mapistore', 'uid_decode_item'), $result); return $result; } /** * Encodes UID element */ protected static function uid_encode_item($str) { $fn = function($match) { return '_' . ord($match[1]); }; $str = preg_replace_callback('/([^0-9a-zA-Z-])/', $fn, $str); return $str; } /** * Decodes UID element */ protected static function uid_decode_item($str) { $fn = function($match) { return chr($match[1]); }; $str = preg_replace_callback('/_([0-9]{2})/', $fn, $str); return $str; } /** * Parse common properties in object data (convert into MAPI format) */ public static function parse_common_props(&$result, $data, $context = array()) { if (empty($context)) { // @TODO: throw exception? return; } if ($data['uid'] && $context['folder_uid']) { $result['id'] = self::uid_encode($context['folder_uid'], $data['uid']); } if ($context['folder_uid']) { $result['parent_id'] = $context['folder_uid']; } foreach (self::$map as $mapi_idx => $kolab_idx) { if (!isset($result[$mapi_idx]) && ($value = $data[$kolab_idx]) !== null) { - switch ($kolab_idx) { - case 'creation-date': - case 'last-modification-date': + switch ($mapi_idx) { + case 'PidTagCreationTime': + case 'PidTagLastModificationTime': $result[$mapi_idx] = self::date_php2mapi($value, true); break; + + case 'PidNameKeywords': + $result[$mapi_idx] = self::parse_categories((array) $value); + break; } } } } /** * Convert common properties into kolab format */ public static function convert_common_props(&$result, $data, $original) { // @TODO: id, parent_id? - foreach (self::$map as $mapi_idx => $kolab_idx) { if (array_key_exists($mapi_idx, $data) && !array_key_exists($kolab_idx, $result)) { $value = $data[$mapi_idx]; switch ($mapi_idx) { case 'PidTagCreationTime': case 'PidTagLastModificationTime': if ($value) { $dt = self::date_mapi2php($value); $result[$kolab_idx] = $dt->format('Y-m-d\TH:i:s\Z'); } break; + + default: + if ($value) { + $result[$kolab_idx] = $value; + } + break; } } } // Handle x-custom fields foreach ((array) $result as $key => $value) { if (strpos($key, 'x-custom.') === 0) { unset($result[$key]); $key = substr($key, 9); foreach ((array) $original['x-custom'] as $idx => $custom) { if ($custom['identifier'] == $key) { if ($value) { $original['x-custom'][$idx]['value'] = $value; } else { unset($original['x-custom'][$idx]); } $x_custom_update = true; continue 2; } } if ($value) { $original['x-custom'][] = array( 'identifier' => $key, 'value' => $value, ); } $x_custom_update = true; } } if ($x_custom_update) { $result['x-custom'] = array_values($original['x-custom']); } } /** * Filter property names */ public function attributes_filter($attrs, $type = null, $reverse = false) { $map = self::$map; $result = array(); if ($type) { $model = $this->get_model_class($type); $map = array_merge($map, $model->map()); } // add some special common attributes $map['PidTagMessageClass'] = 'PidTagMessageClass'; $map['collection'] = 'collection'; $map['id'] = 'uid'; foreach ($attrs as $attr) { if ($reverse) { if ($name = array_search($attr, $map)) { $result[] = $name; } } else if ($name = $map[$attr]) { $result[] = $name; } } return $result; } /** * Return instance of model class object */ protected function get_model_class($type) { $class = "kolab_api_filter_mapistore_$type"; return new $class($this); } /** * Convert DateTime object to MAPI date format */ public function date_php2mapi($date, $utc = true, $time = null) { // convert string to DateTime if (!is_object($date) && !empty($date)) { // convert date to datetime on 00:00:00 if (preg_match('/^([0-9]{4})-?([0-9]{2})-?([0-9]{2})$/', $date, $m)) { $date = $m[1] . '-' . $m[2] . '-' . $m[3] . 'T00:00:00+00:00'; } $date = new DateTime($date); } if (!is_object($date)) { return; } if ($utc) { $date->setTimezone(new DateTimeZone('UTC')); } if (!empty($time)) { $date->setTime((int) $time['hour'], (int) $time['minute'], (int) $time['second']); } // MAPI PTypTime is 64-bit integer representing the number // of 100-nanosecond intervals since January 1, 1601. // Note: probably does not work on 32-bit systems return ($date->format('U') + 11644473600) * 10000000; } /** * Convert date-time from MAPI format to DateTime */ public function date_mapi2php($date) { // Note: probably does not work on 32-bit systems $seconds = intval($date / 10000000) - 11644473600; // assumes we're working with dates after 1970-01-01 return new DateTime('@' . $seconds); } /** * Parse categories according to [MS-OXCICAL 2.1.3.1.1.20.3] * * @param array Categories * * @return array Categories */ public static function parse_categories($categories) { if (!is_array($categories)) { return; } $result = array(); foreach ($categories as $idx => $val) { $val = preg_replace('/(\x3B|\x2C|\x06\x1B|\xFE\x54|\xFF\x1B)/', '', $val); $val = preg_replace('/\s+/', ' ', $val); $val = trim($val); $len = mb_strlen($val); if ($len) { if ($len > 255) { $val = mb_substr($val, 0, 255); } $result[mb_strtolower($val)] = $val; } } return array_values($result); } } diff --git a/lib/filter/mapistore/event.php b/lib/filter/mapistore/event.php index 0497267..cfa172b 100644 --- a/lib/filter/mapistore/event.php +++ b/lib/filter/mapistore/event.php @@ -1,802 +1,797 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_filter_mapistore_event { protected $map = array( // common properties [MS-OXOCAL] 'PidLidAppointmentSequence' => 'sequence', // PtypInteger32 'PidLidBusyStatus' => '', // PtypInteger32, @TODO: X-MICROSOFT-CDO-BUSYSTATUS 'PidLidAppointmentAuxiliaryFlags' => '', // PtypInteger32 'PidLidLocation' => 'location', // PtypString 'PidLidAppointmentStartWhole' => 'dtstart', // PtypTime, UTC 'PidLidAppointmentEndWhole' => 'dtend', // PtypTime, UTC 'PidLidAppointmentDuration' => '', // PtypInteger32, optional - 'PidNameKeywords' => 'categories', // PtypMultipleString 'PidLidAppointmentSubType' => '', // PtypBoolean 'PidLidAppointmentStateFlags' => '', // PtypInteger32 'PidLidResponseStatus' => '', // PtypInteger32 'PidLidRecurring' => '', // PtypBoolean 'PidLidIsRecurring' => '', // PtypBoolean 'PidLidClipStart' => '', // PtypTime 'PidLidClipEnd' => '', // PtypTime 'PidLidAllAttendeesString' => '', // PtypString 'PidLidToAttendeesString' => '', // PtypString 'PidLidCCAttendeesString' => '', // PtypString 'PidLidNonSendableTo' => '', // PtypString 'PidLidNonSendableCc' => '', // PtypString 'PidLidNonSendableBcc' => '', // PtypString 'PidLidNonSendToTrackStatus' => '', // PtypMultipleInteger32 'PidLidNonSendCcTrackStatus' => '', // PtypMultipleInteger32 'PidLidNonSendBccTrackStatus' => '', // PtypMultipleInteger32 'PidLidAppointmentUnsendableRecipients' => '', // PtypBinary, optional 'PidLidAppointmentNotAllowPropose' => '', // PtypBoolean, @TODO: X-MICROSOFT-CDO-DISALLOW-COUNTER 'PidLidGlobalObjectId' => '', // PtypBinary 'PidLidCleanGlobalObjectId' => '', // PtypBinary 'PidTagOwnerAppointmentId' => '', // PtypInteger32, @TODO: X-MICROSOFT-CDO-OWNERAPPTID 'PidTagStartDate' => '', // PtypTime 'PidTagEndDate' => '', // PtypTime 'PidLidCommonStart' => '', // PtypTime 'PidLidCommonEnd' => '', // PtypTime 'PidLidOwnerCriticalChange' => '', // PtypTime, @TODO: X-MICROSOFT-CDO-CRITICAL-CHANGE 'PidLidIsException' => '', // PtypBoolean 'PidTagResponseRequested' => '', // PtypBoolean 'PidTagReplyRequested' => '', // PtypBoolean 'PidLidTimeZoneStruct' => '', // PtypBinary 'PidLidTimeZoneDescription' => '', // PtypString 'PidLidAppointmentTimeZoneDefinitionRecur' => '', // PtypBinary 'PidLidAppointmentTimeZoneDefinitionStartDisplay' => '', // PtypBinary 'PidLidAppointmentTimeZoneDefinitionEndDisplay' => '', // PtypBinary 'PidLidAppointmentRecur' => '', // PtypBinary 'PidLidRecurrenceType' => '', // PtypInteger32 'PidLidRecurrencePattern' => '', // PtypString 'PidLidLinkedTaskItems' => '', // PtypMultipleBinary 'PidLidMeetingWorkspaceUrl' => '', // PtypString 'PidTagIconIndex' => '', // PtypInteger32 'PidLidAppointmentColor' => '', // PtypInteger32 'PidLidAppointmentReplyTime' => '', // @TODO: X-MICROSOFT-CDO-REPLYTIME 'PidLidIntendedBusyStatus' => '', // @TODO: X-MICROSOFT-CDO-INTENDEDSTATUS // calendar object properties [MS-OXOCAL] 'PidTagMessageClass' => '', 'PidLidSideEffects' => '', // PtypInteger32 'PidLidFExceptionAttendees' => '', // PtypBoolean 'PidLidClientIntent' => '', // PtypInteger32 // common props [MS-OXCMSG] 'PidTagSubject' => 'summary', 'PidTagBody' => 'description', 'PidTagHtml' => '', // @TODO: (?) 'PidTagNativeBody' => '', 'PidTagBodyHtml' => '', 'PidTagRtfCompressed' => '', 'PidTagInternetCodepage' => '', 'PidTagContentId' => '', 'PidTagBodyContentLocation' => '', 'PidTagImportance' => 'priority', 'PidTagSensitivity' => 'class', 'PidLidPrivate' => '', 'PidTagCreationTime' => 'created', 'PidTagLastModificationTime' => 'dtstamp', // reminder properties [MS-OXORMDR] 'PidLidReminderSet' => '', // PtypBoolean 'PidLidReminderSignalTime' => '', // PtypTime 'PidLidReminderDelta' => '', // PtypInteger32 'PidLidReminderTime' => '', // PtypTime 'PidLidReminderOverride' => '', // PtypBoolean 'PidLidReminderPlaySound' => '', // PtypBoolean 'PidLidReminderFileParameter' => '', // PtypString 'PidTagReplyTime' => '', // PtypTime 'PidLidReminderType' => '', // PtypInteger32 ); protected $recipient_track_status_map = array( 'TENTATIVE' => 0x00000002, 'ACCEPTED' => 0x00000003, 'DECLINED' => 0x00000004, ); protected $recipient_type_map = array( 'NON-PARTICIPANT' => 0x00000004, 'OPT-PARTICIPANT' => 0x00000002, 'REQ-PARTICIPANT' => 0x00000002, 'CHAIR' => 0x00000001, ); /** * Message importance for PidTagImportance as defined in [MS-OXCMSG] */ protected $importance = array( 0 => 0x00000000, 1 => 0x00000002, 2 => 0x00000002, 3 => 0x00000002, 4 => 0x00000002, 5 => 0x00000001, 6 => 0x00000000, 7 => 0x00000000, 8 => 0x00000000, 9 => 0x00000000, ); /** * Message sesnitivity for PidTagSensitivity as defined in [MS-OXCMSG] */ protected $sensitivity = array( 'public' => 0x00000000, 'personal' => 0x00000001, 'private' => 0x00000002, 'confidential' => 0x00000003, ); /** * Mapping of weekdays */ protected static $recurrence_day_map = array( 'SU' => 0x00000000, 'MO' => 0x00000001, 'TU' => 0x00000002, 'WE' => 0x00000003, 'TH' => 0x00000004, 'FR' => 0x00000005, 'SA' => 0x00000006, 'BYDAY-SU' => 0x00000001, 'BYDAY-MO' => 0x00000002, 'BYDAY-TU' => 0x00000004, 'BYDAY-WE' => 0x00000008, 'BYDAY-TH' => 0x00000010, 'BYDAY-FR' => 0x00000020, 'BYDAY-SA' => 0x00000040, ); /** * Convert Kolab to MAPI * * @param array Data * @param array Context (folder_uid, object_uid, object) * * @return array Data */ public function output($data, $context = null) { $result = array( 'PidTagMessageClass' => 'IPM.Appointment', // mapistore REST API specific properties 'collection' => 'calendars', ); foreach ($this->map as $mapi_idx => $kolab_idx) { if (empty($kolab_idx)) { continue; } $value = kolab_api_filter_mapistore::get_kolab_value($data, $kolab_idx); if ($value === null) { continue; } switch ($mapi_idx) { - case 'PidNameKeywords': - $value = kolab_api_filter_mapistore::parse_categories((array) $value); - break; - case 'PidTagSensitivity': $value = (int) $this->sensitivity[strtolower($value)]; break; case 'PidTagCreationTime': case 'PidTagLastModificationTime': $value = kolab_api_filter_mapistore::date_php2mapi($value, true); break; case 'PidTagImportance': $value = (int) $this->importance[(int) $value]; break; case 'PidLidAppointmentStartWhole': case 'PidLidAppointmentEndWhole': $dt = kolab_api_input_json::to_datetime($value); $value = kolab_api_filter_mapistore::date_php2mapi($dt, true); // PidLidAppointmentTimeZoneDefinitionStartDisplay // PidLidAppointmentTimeZoneDefinitionEndDisplay // this is all-day event if ($dt->_dateonly) { $result['PidLidAppointmentSubType'] = 0x00000001; } break; } $result[$mapi_idx] = $value; } // Organizer if (!empty($data['organizer'])) { $this->add_attendee_to_result($data['organizer'], $result, true); } // Attendees [MS-OXCICAL 2.1.3.1.1.20.2] foreach ((array) $data['attendee'] as $attendee) { $this->add_attendee_to_result($attendee, $result); } // Alarms (MAPI supports only one) foreach ((array) $data['valarm'] as $alarm) { if ($alarm['properties'] && $alarm['properties']['action'] == 'DISPLAY' && ($duration = $alarm['properties']['trigger']['duration']) && ($delta = self::reminder_duration_to_delta($duration)) ) { $result['PidLidReminderDelta'] = $delta; $result['PidLidReminderSet'] = true; // PidLidReminderTime // PidLidReminderSignalTime break; } } // @TODO: PidLidAppointmentDuration // @TODO: exceptions, resources // Recurrence rule if (!empty($data['rrule']) && !empty($data['rrule']['recur'])) { if ($rule = self::recurrence_from_kolab($data['rrule']['recur'], $result)) { $result['PidLidAppointmentRecur'] = $rule; } } kolab_api_filter_mapistore::parse_common_props($result, $data, $context); return $result; } /** * Convert from MAPI to Kolab * * @param array Data * @param array Data of the object that is being updated * * @return array Data */ public function input($data, $object = null) { $result = array(); foreach ($this->map as $mapi_idx => $kolab_idx) { if (empty($kolab_idx)) { continue; } if (!array_key_exists($mapi_idx, $data)) { continue; } $value = $data[$mapi_idx]; switch ($mapi_idx) { case 'PidTagImportance': $map = array( 0x00000002 => 1, 0x00000001 => 5, 0x00000000 => 9, ); $value = (int) $map[(int) $value]; break; case 'PidTagSensitivity': $map = array_flip($this->sensitivity); $value = $map[$value]; break; case 'PidTagCreationTime': case 'PidTagLastModificationTime': if ($value) { $value = kolab_api_filter_mapistore::date_mapi2php($value); $value = $value->format('Y-m-d\TH:i:s\Z'); } break; case 'PidLidAppointmentStartWhole': case 'PidLidAppointmentEndWhole': if ($value) { $value = kolab_api_filter_mapistore::date_mapi2php($value); $format = $data['PidLidAppointmentSubType'] ? 'Y-m-d' : 'Y-m-d\TH:i:s\Z'; $value = $value->format($format); } break; } $result[$kolab_idx] = $value; } // Alarms (MAPI supports only one, DISPLAY) if ($data['PidLidReminderSet'] && ($delta = $data['PidLidReminderDelta'])) { $duration = self::reminder_delta_to_duration($delta); $alarm = array( 'action' => 'DISPLAY', 'trigger' => array('duration' => $duration), 'description' => 'Reminder', ); $result['valarm'] = array(array('properties' => $alarm)); } else if (array_key_exists('PidLidReminderSet', $data) || array_key_exists('PidLidReminderDelta', $data)) { $result['valarm'] = array(); } // Recurrence if (array_key_exists('PidLidAppointmentRecur', $data)) { $result['rrule']['recur'] = $this->recurrence_to_kolab($data['PidLidAppointmentRecur']); } // @TODO: PidLidAppointmentDuration (?) // @TODO: exceptions, resources, attendees kolab_api_filter_mapistore::convert_common_props($result, $data, $object); return $result; } /** * Returns the attributes names mapping */ public function map() { $map = array_filter($this->map); // @TODO: add properties that are not in the map $map['PidLidAppointmentRecur'] = 'rrule'; return $map; } /** * Setting PidTagRecipientType according to [MS-OXCICAL 2.1.3.1.1.20.2] */ protected function to_recipient_type($cutype, $role) { if ($cutype && in_array($cutype, array('RESOURCE', 'ROOM'))) { return 0x00000003; } if ($role && ($type = $this->recipient_type_map[$role])) { return $type; } return 0x00000001; } /** * Convert Kolab 'attendee' specification into MAPI recipient * and add it to the result */ protected function add_attendee_to_result($attendee, &$result, $is_organizer = false) { $email = $attendee['cal-address']; $params = (array) $attendee['parameters']; // parse mailto string if (strpos($email, 'mailto:') === 0) { $email = urldecode(substr($email, 7)); } $emails = rcube_mime::decode_address_list($email, 1); if (!empty($email)) { $email = $emails[key($emails)]; $recipient = array( 'PidTagAddressType' => 'SMTP', 'PidTagDisplayName' => $params['cn'] ?: $email['name'], 'PidTagDisplayType' => 0, 'PidTagEmailAddress' => $email['mailto'], ); if ($is_organizer) { $recipient['PidTagRecipientFlags'] = 0x00000003; $recipient['PidTagRecipientType'] = 0x00000001; } else { $recipient['PidTagRecipientFlags'] = 0x00000001; $recipient['PidTagRecipientTrackStatus'] = (int) $this->recipient_track_status_map[$params['partstat']]; $recipient['PidTagRecipientType'] = $this->to_recipient_type($params['cutype'], $params['role']); } // PidTagEntryId // PidTagRecipientEntryId $recipient['PidTagRecipientDisplayName'] = $recipient['PidTagDisplayName']; $result['recipients'][] = $recipient; if (strtoupper($params['rsvp']) == 'TRUE') { $result['PidTagReplyRequested'] = true; $result['PidTagResponseRequested'] = true; } } } /** * Convert PidLidReminderDelta value into xCal duration */ protected static function reminder_delta_to_duration($delta) { if ($delta == 0x5AE980E1) { $delta = 15; } $delta = (int) $delta; return "-PT{$delta}M"; } /** * Convert Kolab alarm duration into PidLidReminderDelta */ protected static function reminder_duration_to_delta($duration) { if ($duration && preg_match('/^-[PT]*([0-9]+)([WDHMS])$/', $duration, $matches)) { $value = intval($matches[1]); switch ($matches[2]) { case 'S': $value = intval(round($value/60)); break; case 'H': $value *= 60; break; case 'D': $value *= 24 * 60; break; case 'W': $value *= 7 * 24 * 60; break; } return $value; } } /** * Convert Kolab recurrence specification into MAPI properties * * @param array $rule Recurrence rule in Kolab format * @param array $type Object data (MAPI format) * @param string $type Object type (event, task) * * @return object MAPI recurrence in binary format */ public static function recurrence_from_kolab($rule, $object = array(), $type = 'event') { $result = array( 'Period' => $rule['interval'] ? $rule['interval'] : 1, 'FirstDOW' => self::day2bitmask($rule['wkst'] ?: 'MO'), 'OccurrenceCount' => 0x0000000A, 'EndDate' => 0x5AE980DF, 'CalendarType' => kolab_api_filter_mapistore_structure_recurrencepattern::CALENDARTYPE_DEFAULT, // DeletedInstanceDates // ModifiedInstanceDates ); // Get event/task start date for FirstDateTime calculations if ($object['PidLidAppointmentStartWhole']) { $startdate = kolab_api_filter_mapistore::date_mapi2php($object['PidLidAppointmentStartWhole']); $result['StartDate'] = intval($object['PidLidAppointmentStartWhole'] / 10000000 / 60); } else if ($object['PidLidCommonStart']) { $startdate = kolab_api_filter_mapistore::date_mapi2php($object['PidLidCommonStart']); $result['StartDate'] = intval($object['PidLidCommonStart'] / 10000000 / 60); } else { rcube::raise_error(array( 'line' => __LINE__, 'file' => __FILE__, 'message' => "Found recurring $type without start date, skipping recurrence", ), true, false); return; } // $startdate->setTime(0, 0, 0); // @TODO: // StartDate: Set to the date portion of DTSTART, in the time zone specified // by PidLidTimeZoneStruct. This date is stored in minutes after // midnight Jan 1, 1601. Note that this value MUST always be // evenly divisible by 1440. // EndDate: Set to the start date of the last instance of a recurrence, in the // time zone specified by PidLidTimeZoneStruct. This date is // stored in minutes after midnight January 1, 1601. If the // recurrence is infinite, set EndDate to 0x5AE980DF. Note that // this value MUST always be evenly divisible by 1440, except for // the special value 0x5AE980DF. // @TODO: get first occurrence of the event using libcalendaring_recurrence class ? switch ($rule['freq']) { case 'DAILY': $result['RecurFrequency'] = kolab_api_filter_mapistore_structure_recurrencepattern::RECURFREQUENCY_DAILY; $result['PatternType'] = kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_DAY; $result['Period'] *= 1440; break; case 'WEEKLY': // if BYDAY does not exist use day from DTSTART if (empty($rule['byday'])) { $rule['byday'] = strtoupper($startdate->format('S')); } $result['RecurFrequency'] = kolab_api_filter_mapistore_structure_recurrencepattern::RECURFREQUENCY_WEEKLY; $result['PatternType'] = kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_WEEK; $result['PatternTypeSpecific'] = self::day2bitmask($rule['byday'], 'BYDAY-'); break; case 'MONTHLY': $result['RecurFrequency'] = kolab_api_filter_mapistore_structure_recurrencepattern::RECURFREQUENCY_MONTHLY; if (!empty($rule['bymonthday'])) { // MAPI doesn't support multi-valued month days $month_day = min(explode(',', $rule['bymonthday'])); $result['PatternType'] = kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTH; $result['PatternTypeSpecific'] = $month_day == -1 ? 0x0000001F : $month_day; } else { $result['PatternType'] = kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTHNTH; $result['PatternTypeSpecific'][] = self::day2bitmask($rule['byday'], 'BYDAY-'); if (!empty($rule['bysetpos'])) { $result['PatternTypeSpecific'][] = $rule['bysetpos'] == -1 ? 0x00000005 : $rule['bysetpos']; } } break; case 'YEARLY': $result['RecurFrequency'] = kolab_api_filter_mapistore_structure_recurrencepattern::RECURFREQUENCY_YEARLY; $result['Period'] *= 12; // MAPI doesn't support multi-valued months if ($rule['bymonth']) { // @TODO: set $startdate } if (!empty($rule['bymonthday'])) { // MAPI doesn't support multi-valued month days $month_day = min(explode(',', $rule['bymonthday'])); $result['PatternType'] = kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTHNTH; $result['PatternTypeSpecific'] = array(0, $month_day == -1 ? 0x0000001F : $month_day); } else { $result['PatternType'] = kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTHNTH; $result['PatternTypeSpecific'][] = self::day2bitmask($rule['byday'], 'BYDAY-'); if (!empty($rule['bysetpos'])) { $result['PatternTypeSpecific'][] = $rule['bysetpos'] == -1 ? 0x00000005 : $rule['bysetpos']; } } break; } if (!empty($rule['until'])) { $result['EndDate'] = intval(kolab_api_filter_mapistore::date_php2mapi($rule['until']) / 10000000 / 60); // @TODO: calculate OccurrenceCount? $result['EndType'] = kolab_api_filter_mapistore_structure_recurrencepattern::ENDTYPE_AFTER; } else if (!empty($rule['count'])) { $result['EndType'] = kolab_api_filter_mapistore_structure_recurrencepattern::ENDTYPE_NOCC; $result['OccurrenceCount'] = $rule['count']; // @TODO: set EndDate } else { $result['EndType'] = kolab_api_filter_mapistore_structure_recurrencepattern::ENDTYPE_NEVER; } $result['FirstDateTime'] = self::date_minutes_diff($startdate); $result = new kolab_api_filter_mapistore_structure_recurrencepattern($result); if ($type == 'task') { return $result->output(true); } // @TODO: exceptions $byhour = $rule['byhour'] ? min(explode(',', $rule['byhour'])) : 0; $byminute = $rule['byminute'] ? min(explode(',', $rule['byminute'])) : 0; $offset = 60 * intval($byhour) + intval($byminute); $arp = array( 'RecurrencePattern' => $result, 'StartTimeOffset' => $offset, 'EndTimeOffset' => $offset + $object['PidLidAppointmentDuration'], // ExceptionInfo // ExtendedExceptions ); $result = new kolab_api_filter_mapistore_structure_appointmentrecurrencepattern($arp); return $result->output(true); } /** * Convert MAPI recurrence into Kolab (MS-OXICAL: 2.1.3.2.2) * * @param string $rule MAPI binary representation of recurrence rule * @param string $type Object type (task, event) * * @return array Recurrence rule in Kolab format */ public static function recurrence_to_kolab($rule, $type = 'event') { if (empty($rule)) { return array(); } // parse binary (Appointment)RecurrencePattern if ($type == 'event') { $arp = new kolab_api_filter_mapistore_structure_appointmentrecurrencepattern(); $arp->input($rule, true); $rp = $arp->RecurrencePattern; } else { $rp = new kolab_api_filter_mapistore_structure_recurrencepattern(); $rp->input($rule, true); } $result = array( 'interval' => $rp->Period, ); switch ($rp->PatternType) { case kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_DAY: $result['freq'] = 'DAILY'; $result['interval'] /= 1440; if ($arp) { $result['byhour'] = floor($arp->StartTimeOffset / 60); $result['byminute'] = $arp->StartTimeOffset - $result['byhour'] * 60; } break; case kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_WEEK: $result['freq'] = 'WEEKLY'; $result['byday'] = self::bitmask2day($rp->PatternTypeSpecific); if ($rp->Period >= 1) { $result['wkst'] = self::bitmask2day($rp->FirstDOW); } break; default: // monthly/yearly $evenly_divisible = $rp->Period % 12 == 0; switch ($rp->PatternType) { case kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTH: case kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTHEND: $result['freq'] = $evenly_divisible ? 'YEARLY' : 'MONTHLY'; break; case kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTHNTH: case kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_HJMONTHNTH: $result['freq'] = $evenly_divisible ? 'YEARLY-NTH' : 'MONTHLY-NTH'; break; default: // not-supported return; } if ($result['freq'] = 'MONTHLY') { $rule['bymonthday'] = intval($rp->PatternTypeSpecific == 0x0000001F ? -1 : $rp->PatternTypeSpecific); } else if ($result['freq'] = 'MONTHLY-NTH') { $result['freq'] = 'MONTHLY'; $result['byday'] = self::bitmask2day($rp->PatternTypeSpecific[0]); if ($rp->PatternTypeSpecific[1]) { $result['bysetpos'] = intval($rp->PatternTypeSpecific[1] == 0x00000005 ? -1 : $rp->PatternTypeSpecific[1]); } } else if ($result['freq'] = 'YEARLY') { $result['interval'] /= 12; $rule['bymonthday'] = intval($rp->PatternTypeSpecific == 0x0000001F ? -1 : $rp->PatternTypeSpecific); $rule['bymonth'] = 0;// @TODO: month from FirstDateTime } else if ($result['freq'] = 'YEARLY-NTH') { $result['freq'] = 'YEARLY'; $result['interval'] /= 12; $result['byday'] = self::bitmask2day($rp->PatternTypeSpecific[0]); $result['bymonth'] = 0;// @TODO: month from FirstDateTime if ($rp->PatternTypeSpecific[1]) { $result['bysetpos'] = intval($rp->PatternTypeSpecific[1] == 0x00000005 ? -1 : $rp->PatternTypeSpecific[1]); } } } if ($rp->EndType == kolab_api_filter_mapistore_structure_recurrencepattern::ENDTYPE_AFTER) { // @TODO: set UNTIL to EndDate + StartTimeOffset, or the midnight of EndDate } else if ($rp->EndType == kolab_api_filter_mapistore_structure_recurrencepattern::ENDTYPE_NOCC) { $result['count'] = $rp->OccurrenceCount; } if ($result['interval'] == 1) { unset($result['interval']); } return $result; } /** * Converts string of days (TU,TH) to bitmask used by MAPI * * @param string $days * * @return int */ protected static function day2bitmask($days, $prefix = '') { $days = explode(',', $days); $result = 0; foreach ($days as $day) { $result = $result + self::$recurrence_day_map[$prefix.$day]; } return $result; } /** * Convert bitmask used by MAPI to string of days (TU,TH) * * @param int $days * * @return string */ protected static function bitmask2day($days) { $days_arr = array(); foreach (self::$recurrence_day_map as $day => $bit) { if ($days & $bit) { $days_arr[] = preg_replace('/^[A-Z-]+/', '', $day); } } $result = implode(',', $days_arr); return $result; } /** * Returns number of minutes between midnight 1601-01-01 * and specified UTC DateTime */ protected static function date_minutes_diff($date) { $start = new DateTime('1601-01-01 00:00:00 +00:00'); // make sure the specified date is in UTC $date->setTimezone(new DateTimeZone('UTC')); return round(($date->getTimestamp() - $start->getTimestamp()) * 60); } } diff --git a/lib/kolab_api_backend.php b/lib/kolab_api_backend.php index 47a5bc2..fee9bc1 100644 --- a/lib/kolab_api_backend.php +++ b/lib/kolab_api_backend.php @@ -1,1026 +1,1177 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_backend { /** * Singleton instace of kolab_api_backend * * @var kolab_api_backend */ static protected $instance; public $api; public $storage; public $username; public $password; public $delimiter; protected $icache = array(); /** * This implements the 'singleton' design pattern * * @return kolab_api_backend The one and only instance */ static function get_instance() { if (!self::$instance) { self::$instance = new kolab_api_backend; self::$instance->startup(); // init AFTER object was linked with self::$instance } return self::$instance; } /** * Class initialization */ public function startup() { $this->api = kolab_api::get_instance(); $this->storage = $this->api->get_storage(); // @TODO: reset cache? if we do this for every request the cache would be useless // There's no session here //$this->storage->clear_cache('mailboxes.', true); // set additional header used by libkolab $this->storage->set_options(array( // @TODO: there can be Roundcube plugins defining additional headers, // we maybe would need to add them here 'fetch_headers' => 'X-KOLAB-TYPE X-KOLAB-MIME-VERSION', 'skip_deleted' => true, 'threading' => false, )); // Disable paging $this->storage->set_pagesize(999999); $this->delimiter = $this->storage->get_hierarchy_delimiter(); } /** * Authenticate a user * * @param string Username * @param string Password * * @return bool */ public function authenticate($username, $password) { $host = $this->select_host($username); // use shared cache for kolab_auth plugin result (username canonification) $cache = $this->api->get_cache_shared('kolab_api_auth'); $cache_key = sha1($username . '::' . $host); if (!$cache || !($auth = $cache->get($cache_key))) { $auth = $this->api->plugins->exec_hook('authenticate', array( 'host' => $host, 'user' => $username, 'pass' => $password, )); if ($cache && !$auth['abort']) { $cache->set($cache_key, array( 'user' => $auth['user'], 'host' => $auth['host'], )); } // LDAP server failure... send 503 error if ($auth['kolab_ldap_error']) { throw new kolab_api_exception(kolab_api_exception::UNAVAILABLE); } } else { $auth['pass'] = $password; } // authenticate user against the IMAP server $user_id = $auth['abort'] ? 0 : $this->login($auth['user'], $auth['pass'], $auth['host'], $error); if ($user_id) { $this->username = $auth['user']; $this->password = $auth['pass']; $this->delimiter = $this->storage->get_hierarchy_delimiter(); return true; } // IMAP server failure... send 503 error if ($error == rcube_imap_generic::ERROR_BAD) { throw new kolab_api_exception(kolab_api_exception::UNAVAILABLE); } return false; } /** * Get list of folders * * @param string $type Folder type * * @return array|bool List of folders, False on backend failure */ public function folders_list($type = null) { $type_keys = array( kolab_storage::CTYPE_KEY_PRIVATE, kolab_storage::CTYPE_KEY, ); // get folder unique identifiers and types $uid_data = $this->folder_uids(); $type_data = $this->storage->get_metadata('*', $type_keys); $folders = array(); if (!is_array($type_data)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } foreach ($uid_data as $folder => $uid) { $path = strpos($folder, '&') === false ? $folder : rcube_charset::convert($folder, 'UTF7-IMAP'); if (strpos($path, $this->delimiter)) { $list = explode($this->delimiter, $path); $name = array_pop($list); $parent = implode($this->delimiter, $list); $parent_id = null; if ($folders[$parent]) { $parent_id = $folders[$parent]['uid']; } // parent folder does not exist add it to the list else { for ($i=0; $idelimiter, $parent_arr); if ($folders[$parent]) { $parent_id = $folders[$parent]['uid']; } else { $fid = $this->folder_name2uid(rcube_charset::convert($parent, RCUBE_CHARSET, 'UTF7-IMAP')); $folders[$parent] = array( 'name' => array_pop($parent_arr), 'fullpath' => $parent, 'uid' => $fid, 'parent' => $parent_id, ); $parent_id = $fid; } } } } else { $parent_id = null; $name = $path; } $data = array( 'name' => $name, 'fullpath' => $path, 'parent' => $parent_id, 'uid' => $uid, ); // folder type reset($type_keys); foreach ($type_keys as $key) { $data['type'] = $type_data[$folder][$key]; break; } if (empty($data['type'])) { $data['type'] = 'mail'; } $folders[$path] = $data; } // sort folders uksort($folders, array($this, 'sort_folder_comparator')); return $folders; } /** * Returns folder type * * @param string $uid Folder unique identifier * @param string $with_suffix Enable to not remove the subtype * * @return string Folder type */ public function folder_type($uid, $with_suffix = false) { $folder = $this->folder_uid2name($uid); $type = kolab_storage::folder_type($folder); if ($type === null) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } if (!$with_suffix) { list($type, ) = explode('.', $type); } return $type; } /** * Returns objects in a folder * * @param string $uid Folder unique identifier * * @return array Objects (of type rcube_message_header or kolab_format) * @throws kolab_api_exception */ public function objects_list($uid) { $type = $this->folder_type($uid); // use IMAP to fetch mail messages if ($type === 'mail') { $folder = $this->folder_uid2name($uid); $result = $this->storage->list_messages($folder, 1); } // otherwise use kolab_storage else { $folder = $this->folder_get_by_uid($uid, $type); $result = $folder->get_objects(); if ($result === null) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } return $result; } /** * Counts objects in a folder * * @param string $uid Folder unique identifier * * @return int Objects count * @throws kolab_api_exception */ public function objects_count($uid) { $type = $this->folder_type($uid); // use IMAP to count mail messages if ($type === 'mail') { $folder = $this->folder_uid2name($uid); // @TODO: error checking requires changes in rcube_imap $result = $this->storage->count($folder, 'ALL'); } // otherwise use kolab_storage else { $folder = $this->folder_get_by_uid($uid, $type); $result = $folder->count(); } return $result; } /** * Delete objects in a folder * * @param string $uid Folder unique identifier * @param string|array $set List of object IDs or "*" for all * * @throws kolab_api_exception */ public function objects_delete($uid, $set) { $type = $this->folder_type($uid); if ($type === 'mail') { $is_mail = true; $folder = $this->folder_uid2name($uid); } // otherwise use kolab_storage else { $folder = $this->folder_get_by_uid($uid, $type); } // delete all if ($set === "*") { if ($is_mail) { $result = $this->storage->clear_folder($folder); } else { $result = $folder->delete_all(); } } else { if ($is_mail) { $result = $this->storage->delete_message($set, $folder); } else { foreach ($set as $uid) { $result = $folder->delete($uid); if ($result === false) { break; } } } } if ($result === false) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } /** * Get object data * * @param string $folder_uid Folder unique identifier * @param string $uid Object identifier * * @return rcube_message|array Object data * @throws kolab_api_exception */ public function object_get($folder_uid, $uid) { $type = $this->folder_type($folder_uid); if ($type === 'mail') { $folder = $this->folder_uid2name($folder_uid); $object = new rcube_message($uid, $folder); if (!$object || empty($object->headers)) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } } // otherwise use kolab_storage else { $folder = $this->folder_get_by_uid($folder_uid, $type); if (!$folder || !$folder->valid) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } $object = $folder->get_object($uid); if (!$object) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } + + $old_categories = $object['categories']; + } + + // @TODO: Use relations also for events + if ($type != 'configuration' && $type != 'event') { + // get object categories (tag-relations) + $categories = $this->get_tags($object, $old_categories); + + if ($type === 'mail') { + $object->categories = $categories; + } + else { + $object['categories'] = $categories; + } } return $object; } /** * Create an object * * @param string $folder_uid Folder unique identifier * @param array $data Object data * @param string $type Object type * * @return string Object UID * @throws kolab_api_exception */ public function object_create($folder_uid, $data, $type) { $ftype = $this->folder_type($folder_uid); if ($type === 'mail') { if ($ftype !== 'mail') { throw new kolab_api_exception(kolab_api_exception::INVALID_REQUEST); } $folder = $this->folder_uid2name($folder_uid); // @TODO } // otherwise use kolab_storage else { + // @TODO: Use relations also for events + if (!preg_match('/^(event|configuration)/', $type)) { + // get object categories (tag-relations) + $categories = (array) $data['categories']; + $data['categories'] = array(); + } + $folder = $this->folder_get_by_uid($folder_uid, $type); if (!$folder || !$folder->valid) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } if (!$folder->save($data)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } + // @TODO: Use relations also for events + if (!empty($categories)) { + // create/assign categories (tag-relations) + $this->set_tags($data['uid'], $categories); + } + return $data['uid']; } } /** * Update an object * * @param string $folder_uid Folder unique identifier * @param array $data Object data * @param string $type Object type * * @throws kolab_api_exception */ public function object_update($folder_uid, $data, $type) { $ftype = $this->folder_type($folder_uid); if ($type === 'mail') { if ($ftype != 'mail') { throw new kolab_api_exception(kolab_api_exception::INVALID_REQUEST); } $folder = $this->folder_uid2name($folder_uid); // @TODO } // otherwise use kolab_storage else { + // @TODO: Use relations also for events + if (!preg_match('/^(event|configuration)/', $type)) { + // get object categories (tag-relations) + $categories = (array) $data['categories']; + $data['categories'] = array(); + } + $folder = $this->folder_get_by_uid($folder_uid, $type); if (!$folder || !$folder->valid) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } if (!$folder->save($data)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } + + // @TODO: Use relations also for events + if (array_key_exists('categories', $data)) { + // create/assign categories (tag-relations) + $this->set_tags($data['uid'], $categories); + } } } /** * Get attachment body * * @param mixed $object Object data (from self::object_get()) * @param string $part_id Attachment part identifier * @param mixed $mode NULL to return a string, -1 to print body * or file pointer to save the body into * * @return string Attachment body if $fp=null * @throws kolab_api_exception */ public function attachment_get($object, $part_id, $mode = null) { // object is a mail message if ($object instanceof rcube_message) { return $object->get_part_body($part_id, false, 0, $mode); } // otherwise use kolab_storage else { return $this->storage->get_message_part($this->uid, $part_id, null, $mode === -1, is_resource($mode) ? $mode : null, true, 0, false); } } + /** + * Delete an attachment from the message + * + * @param mixed $object Object data (from self::object_get()) + * @param string $id Attachment identifier + * + * @return boolean|string True or message UID (if changed) + * @throws kolab_api_exception + */ + public function attachment_delete($object, $id) + { + // object is a mail message + if ($object instanceof rcube_message) { + // @TODO + } + // otherwise use kolab_storage + else { + $folder = kolab_storage::get_folder($object['_mailbox']); + + if (!$folder || !$folder->valid) { + throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); + } + + $found = false; + + // unset the attachment + foreach ((array) $object['_attachments'] as $idx => $att) { + if ($att['id'] == $id) { + $object['_attachments'][$idx] = false; + $found = true; + } + } + + if (!$found) { + throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); + } + + if (!$folder->save($data)) { + throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); + } + + return true; + } + } + /** * Creates a folder * * @param string $name Folder name (UTF-8) * @param string $parent Parent folder identifier * @param string $type Folder type * * @return bool Folder identifier on success */ public function folder_create($name, $parent = null, $type = null) { $name = rcube_charset::convert($name, RCUBE_CHARSET, 'UTF7-IMAP'); if ($parent) { $parent = $this->folder_uid2name($parent); $name = $parent . $this->delimiter . $name; } if ($this->storage->folder_exists($name)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } $created = kolab_storage::folder_create($name, $type, false, false); if ($created) { $created = $this->folder_name2uid($name); } return $created; } /** * Subscribes a folder * * @param string $uid Folder identifier * @param array $updates Updates (array with keys type, subscribed, active) * * @throws kolab_api_exception */ public function folder_update($uid, $updates) { $folder = $this->folder_uid2name($uid); if (isset($updates['type'])) { $result = kolab_storage::set_folder_type($folder, $updates['type']); if (!$result) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } if (isset($updates['subscribed'])) { if ($updates['subscribed']) { $result = $this->storage->subscribe($folder); } else { $result = $this->storage->unsubscribe($folder); } if (!$result) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } // @TODO: active state } /** * Renames a folder * * @param string $old_name Folder name (UTF-8) * @param string $new_name New folder name (UTF-8) * * @throws kolab_api_exception */ public function folder_rename($old_name, $new_name) { $old_name = rcube_charset::convert($old_name, RCUBE_CHARSET, 'UTF7-IMAP'); $new_name = rcube_charset::convert($new_name, RCUBE_CHARSET, 'UTF7-IMAP'); if (!strlen($old_name) || !strlen($new_name) || $old_name === $new_name) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } if ($this->storage->folder_exists($new_name)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } // don't use kolab_storage for moving mail folders if (preg_match('/^mail/', $type)) { $result = $this->storage->rename_folder($old_name, $new_name); } else { $result = kolab_storage::folder_rename($old_name, $new_name); } if (!$result) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } /** * Deletes folder * * @param string $uid Folder UID * * @return bool True on success, False on failure * @throws kolab_api_exception */ public function folder_delete($uid) { $folder = $this->folder_uid2name($uid); $type = $this->folder_type($uid); // don't use kolab_storage for mail folders if ($type === 'mail') { $status = $this->storage->delete_folder($folder); } else { $status = kolab_storage::folder_delete($folder); } if (!$status) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } /** * Folder info * * @param string $uid Folder UID * * @return array Folder information * @throws kolab_api_exception */ public function folder_info($uid) { $folder = $this->folder_uid2name($uid); // get IMAP folder info $info = $this->storage->folder_info($folder); // get IMAP folder data $data = $this->storage->folder_data($folder); $info['exists'] = $data['EXISTS']; $info['unseen'] = $data['UNSEEN']; $info['modseq'] = $data['HIGHESTMODSEQ']; // add some more parameters (used in folders list response) $path = strpos($folder, '&') === false ? $folder : rcube_charset::convert($folder, 'UTF7-IMAP'); $path = explode($this->delimiter, $path); $info['name'] = array_pop($path); $info['fullpath'] = implode($this->delimiter, $path); $info['uid'] = $uid; $info['type'] = kolab_storage::folder_type($folder, true) ?: 'mail'; if ($info['fullpath'] !== '') { $parent = $this->folder_name2uid(rcube_charset::convert($info['fullpath'], RCUBE_CHARSET, 'UTF7-IMAP')); $info['parent'] = $parent; } // convert some info to be more compact if (!empty($info['rights'])) { $info['rights'] = implode('', $info['rights']); } // @TODO: subscription status, active state // some info is not very interesting here ;) unset($info['attributes']); return $info; } /** * Returns IMAP folder name with full path * * @param string $uid Folder identifier * * @return string Folder full path (UTF-8) */ public function folder_uid2path($uid) { $folder = $this->folder_uid2name($uid); return strpos($folder, '&') === false ? $folder : rcube_charset::convert($folder, 'UTF7-IMAP'); } /** * Returns IMAP folder name * * @param string $uid Folder identifier * * @return string Folder name (UTF7-IMAP) */ protected function folder_uid2name($uid) { if ($uid === null || $uid === '') { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } // we store last folder in-memory if (isset($this->icache["folder:$uid"])) { return $this->icache["folder:$uid"]; } $uids = $this->folder_uids(); foreach ($uids as $folder => $_uid) { if ($uid === $_uid) { return $this->icache["folder:$uid"] = $folder; } } // slowest method, but we need to try it, the full folders list // might contain non-existing folder (not in folder_uids() result) foreach ($this->folders_list as $folder) { if ($folder['uid'] === $uid) { return rcube_charset::convert($folder['fullpath'], RCUBE_CHARSET, 'UTF7-IMAP'); } } throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } /** * Helper method to get folder UID * * @param string $folder Folder name (UTF7-IMAP) * * @return string Folder's UID */ protected function folder_name2uid($folder) { $uid_keys = array( kolab_storage::UID_KEY_CYRUS, ); // get folder identifiers $metadata = $this->storage->get_metadata($folder, $uid_keys); if (!is_array($metadata) && $this->storage->get_error_code() != rcube_imap_generic::ERROR_NO) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } // above we assume that cyrus built-in unique identifiers are available // however, if they aren't we'll try kolab folder UIDs if (empty($metadata)) { $uid_keys = array( kolab_storage::UID_KEY_PRIVATE, kolab_storage::UID_KEY_SHARED, ); // get folder identifiers $metadata = $this->storage->get_metadata($folder, $uid_keys); if (!is_array($metadata) && $this->storage->get_error_code() != rcube_imap_generic::ERROR_NO) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } if (!empty($metadata[$folder])) { foreach ($uid_keys as $key) { if ($uid = $metadata[$folder][$key]) { return $uid; } } } return md5($folder); /* // @TODO: // make sure folder exists // generate a folder UID and set it to IMAP $uid = rtrim(chunk_split(md5($folder . $this->get_owner() . uniqid('-', true)), 12, '-'), '-'); if (!$this->storage->set_metadata($folder, array(kolab_storage::UID_KEY_SHARED => $uid))) { if ($this->storage->set_metadata($folder, array(kolab_storage::UID_KEY_PRIVATE => $uid))) { return $uid; } } // create hash from folder name if we can't write the UID metadata return md5($folder . $this->get_owner()); */ } /** * Callback for uasort() that implements correct * locale-aware case-sensitive sorting */ protected function sort_folder_comparator($str1, $str2) { $path1 = explode($this->delimiter, $str1); $path2 = explode($this->delimiter, $str2); foreach ($path1 as $idx => $folder1) { $folder2 = $path2[$idx]; if ($folder1 === $folder2) { continue; } return strcoll($folder1, $folder2); } } /** * Return UIDs of all folders * * @return array Folder name to UID map */ protected function folder_uids() { $uid_keys = array( kolab_storage::UID_KEY_CYRUS, ); // get folder identifiers $metadata = $this->storage->get_metadata('*', $uid_keys); if (!is_array($metadata)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } // above we assume that cyrus built-in unique identifiers are available // however, if they aren't we'll try kolab folder UIDs if (empty($metadata)) { $uid_keys = array( kolab_storage::UID_KEY_PRIVATE, kolab_storage::UID_KEY_SHARED, ); // get folder identifiers $metadata = $this->storage->get_metadata('*', $uid_keys); if (!is_array($metadata)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } $lambda = function(&$item, $key, $keys) { reset($keys); foreach ($keys as $key) { $item = $item[$key]; return; } }; array_walk($metadata, $lambda, $uid_keys); return $metadata; } /** * Get folder by UID (use only for non-mail folders) * * @param string $uid Folder UID * @param string $type Folder type * * @return kolab_storage_folder Folder object * @throws kolab_api_exception */ protected function folder_get_by_uid($uid, $type = null) { $folder = $this->folder_uid2name($uid); $folder = kolab_storage::get_folder($folder, $type); if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } // Check the given storage folder instance for validity and throw // the right exceptions according to the error state. if (!$folder->valid || ($error = $folder->get_error())) { if ($error === kolab_storage::ERROR_IMAP_CONN) { throw new kolab_api_exception(kolab_api_exception::UNAVAILABLE); } else if ($error === kolab_storage::ERROR_CACHE_DB) { throw new kolab_api_exception(kolab_api_exception::UNAVAILABLE); } else if ($error === kolab_storage::ERROR_NO_PERMISSION) { throw new kolab_api_exception(kolab_api_exception::FORBIDDEN); } else if ($error === kolab_storage::ERROR_INVALID_FOLDER) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } return $folder; } /** * Storage host selection */ protected function select_host($username) { // Get IMAP host $host = $this->api->config->get('default_host', 'localhost'); if (is_array($host)) { list($user, $domain) = explode('@', $username); // try to select host by mail domain if (!empty($domain)) { foreach ($host as $storage_host => $mail_domains) { if (is_array($mail_domains) && in_array_nocase($domain, $mail_domains)) { $host = $storage_host; break; } else if (stripos($storage_host, $domain) !== false || stripos(strval($mail_domains), $domain) !== false) { $host = is_numeric($storage_host) ? $mail_domains : $storage_host; break; } } } // take the first entry if $host is not found if (is_array($host)) { list($key, $val) = each($default_host); $host = is_numeric($key) ? $val : $key; } } return rcube_utils::parse_host($host); } /** * Authenticates a user in IMAP and returns Roundcube user ID. */ protected function login($username, $password, $host, &$error = null) { if (empty($username)) { return null; } $login_lc = $this->api->config->get('login_lc'); $default_port = $this->api->config->get('default_port', 143); // parse $host $a_host = parse_url($host); if ($a_host['host']) { $host = $a_host['host']; $ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; if (!empty($a_host['port'])) { $port = $a_host['port']; } else if ($ssl && $ssl != 'tls' && (!$default_port || $default_port == 143)) { $port = 993; } } if (!$port) { $port = $default_port; } // Convert username to lowercase. If storage backend // is case-insensitive we need to store always the same username if ($login_lc) { if ($login_lc == 2 || $login_lc === true) { $username = mb_strtolower($username); } else if (strpos($username, '@')) { // lowercase domain name list($local, $domain) = explode('@', $username); $username = $local . '@' . mb_strtolower($domain); } } // Here we need IDNA ASCII // Only rcube_contacts class is using domain names in Unicode $host = rcube_utils::idn_to_ascii($host); $username = rcube_utils::idn_to_ascii($username); // user already registered? if ($user = rcube_user::query($username, $host)) { $username = $user->data['username']; } // authenticate user in IMAP if (!$this->storage->connect($host, $username, $password, $port, $ssl)) { $error = $this->storage->get_error_code(); return null; } // No user in database, but IMAP auth works if (!is_object($user)) { if ($this->api->config->get('auto_create_user')) { // create a new user record $user = rcube_user::create($username, $host); if (!$user) { rcube::raise_error(array( 'code' => 620, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Failed to create a user record", ), true, false); return null; } } else { rcube::raise_error(array( 'code' => 620, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Access denied for new user $username. 'auto_create_user' is disabled", ), true, false); return null; } } // overwrite config with user preferences $this->user = $user; $this->api->config->set_user_prefs((array)$this->user->get_prefs()); setlocale(LC_ALL, 'en_US.utf8', 'en_US.UTF-8'); return $user->ID; } + + /** + * Returns list of tag-relation names assigned to kolab object + */ + protected function get_tags($object, $categories = null) + { + // Kolab object + if (is_array($object)) { + $ident = $object['uid']; + } + // Mail message + else if (is_object($object)) { + // support only messages with message-id + $ident = $object->headers->get('message-id', false); + $folder = $message->folder; + $uid = $message->uid; + } + + if (empty($ident)) { + return array(); + } + + $config = kolab_storage_config::get_instance(); + $tags = $config->get_tags($ident); + $delta = 300; + + // resolve members if it wasn't done recently + if ($uid) { + foreach ($tags as $idx => $tag) { + $force = empty($this->tag_rts[$tag['uid']]) || $this->tag_rts[$tag['uid']] <= time() - $delta; + $members = $config->resolve_members($tag, $force); + + if (empty($members[$folder]) || !in_array($uid, $members[$folder])) { + unset($tags[$idx]); + } + + if ($force) { + $this->tag_rts[$tag['uid']] = time(); + } + } + + // make sure current folder is set correctly again + $this->storage->set_folder($folder); + } + + $tags = array_filter(array_map(function($v) { return $v['name']; }, $tags)); + + // merge result with old categories + if (!empty($categories)) { + $tags = array_unique(array_merge($tags, (array) $categories)); + } + + return $tags; + } + + /** + * Set tag-relations to kolab object + */ + protected function set_tags($uid, $tags) + { + // @TODO: set_tags() for email + + $config = kolab_storage_config::get_instance(); + $config->save_tags($uid, $tags); + } } diff --git a/lib/output/json.php b/lib/output/json.php index 01d31d0..b187706 100644 --- a/lib/output/json.php +++ b/lib/output/json.php @@ -1,241 +1,247 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_output_json extends kolab_api_output { /** * Send successful response * * @param mixed Response data * @param string Data type * @param array Context (folder_uid, object_uid, object) * @param array Optional attributes filter */ public function send($data, $type, $context = null, $attrs_filter = array()) { // Set output type $this->headers(array('Content-Type' => "application/json; charset=utf-8")); list($type, $mode) = explode('-', $type); if ($mode != 'list') { $data = array($data); } $class = "kolab_api_output_json_$type"; $model = new $class($this); $result = array(); $debug = $this->api->config->get('kolab_api_debug'); foreach ($data as $idx => $item) { if ($element = $model->element($item, $attrs_filter)) { $result[] = $element; } else { unset($data[$idx]); } } // apply output filter if ($this->api->filter) { $this->api->filter->output($result, $type, $context, $attrs_filter); } // generate JSON output $opts = $debug && defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0; $result = json_encode($result, $opts); if ($mode != 'list') { $result = trim($result, '[]'); } if ($debug) { rcube::console($result); } // send JSON output echo $result; exit; } /** * Convert object data into JSON API format * * @param array Object data * @param string Object type * * @return array Object data in JSON API format */ public function convert($data, $type) { $class = "kolab_api_output_json_$type"; $model = new $class($this); return $model->element($data); } /** * Convert (part of) kolab_format object into an array * * @param array Kolab object * @param string Object type * @param string Data element name * @param array Optional list of return properties * * @return array Object data */ public function object_to_array($object, $type, $element, $properties = array(), $array_elements = array()) { // load old object to preserve data we don't understand/process if (is_object($object['_formatobj'])) { $format = $object['_formatobj']; } // create new kolab_format instance if (!$format) { $format = kolab_format::factory($type, kolab_storage::$version); if (PEAR::isError($format)) { return; } $format->set($object); } $xml = $format->write(kolab_storage::$version); if (empty($xml) || !$format->is_valid() || !$format->uid) { return; } // The simplest way of "normalizing object properties // is to use its XML representation $doc = new DOMDocument(); // LIBXML_NOBLANKS is required for xml_to_array() below $doc->loadXML($xml, LIBXML_NOBLANKS); $node = $doc->getElementsByTagName($element)->item(0); $node = $this->xml_to_array($node); $node = array_filter($node); unset($node['prodid']); + // faked 'categories' property (we need this for unit-tests + // @TODO: find a better way + if (!empty($object['categories'])) { + $node['categories'] = $object['categories']; + } + if (!empty($properties)) { $node = array_intersect_key($node, array_combine($properties, $properties)); } // force some elements to be arrays if (!empty($array_elements)) { self::parse_array_result($node, $array_elements); } return $node; } /** * Convert XML element into an array * This is intended to use with Kolab XML format * * @param DOMElement XML element * * @return mixed Conversion result */ public function xml_to_array($node) { $children = $node->childNodes; if (!$children->length) { return; } if ($children->length == 1) { if ($node->firstChild->nodeType == XML_TEXT_NODE || !$node->firstChild->childNodes->length ) { return (string) $node->textContent; } if ($node->firstChild->nodeType == XML_ELEMENT_NODE && $node->firstChild->childNodes->length == 1 && $node->firstChild->firstChild->nodeType == XML_TEXT_NODE ) { switch ($node->firstChild->nodeName) { case 'integer': return (int) $node->textContent; case 'boolean': return strtoupper($node->textContent) == 'TRUE'; case 'date-time': case 'timestamp': case 'date': case 'text': case 'uri': case 'sex': return (string) $node->textContent; } } } $result = array(); foreach ($children as $child) { $value = $child->nodeType == XML_TEXT_NODE ? $child->nodeValue : $this->xml_to_array($child); if (!isset($result[$child->nodeName])) { $result[$child->nodeName] = $value; } else { if (!is_array($result[$child->nodeName]) || !isset($result[$child->nodeName][0])) { $result[$child->nodeName] = array($result[$child->nodeName]); } $result[$child->nodeName][] = $value; } } if (is_array($result['text']) && count($result) == 1) { $result = $result['text']; } return $result; } public static function parse_array_result(&$data, $array_elements = array()) { foreach ($array_elements as $key) { $items = explode('/', $key); if (count($items) > 1 && !empty($data[$items[0]])) { $key = array_shift($items); self::parse_array_result($data[$key], array(implode('/', $items))); } else if (!empty($data[$key]) && (!is_array($data[$key]) || !array_key_exists(0, $data[$key]))) { $data[$key] = array($data[$key]); } } } } diff --git a/lib/output/json/mail.php b/lib/output/json/mail.php index d6da415..a26d1b1 100644 --- a/lib/output/json/mail.php +++ b/lib/output/json/mail.php @@ -1,154 +1,155 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_output_json_mail { protected $output; /** * Object constructor * * @param kolab_api_output Output object */ public function __construct($output) { $this->output = $output; } /** * Convert message data into an array * * @param rcube_message|rcube_message_header Message data * @param array Optional attributes filter * * @return array Data */ public function element($data, $attrs_filter = array()) { $is_header = $data instanceof rcube_message_header; $headers = $is_header ? $data : $data->headers; $result = array(); // supported header fields $header_fields = array( 'uid', 'subject', 'from', 'to', 'cc', 'bcc', 'reply-to', 'date', 'internaldate', 'content-type', 'priority', 'size', 'flags', + 'categories', ); if (!empty($attrs_filter)) { $header_fields = array_intersect($header_fields, $attrs_filter); } foreach ($header_fields as $field) { $value = null; switch ($field) { case 'uid': $value = (string) $headers->uid; break; case 'priority': case 'size': if (isset($headers->{$field})) { $value = (int) $headers->{$field}; } break; case 'content-type': $value = $headers->ctype; if ($pos = strpos($value, ';')) { $value = substr($value, 0, $pos); } break; case 'date': case 'internaldate': $value = $headers->{$field}; break; case 'subject': $value = trim(rcube_mime::decode_header($headers->subject, $headers->charset)); break; case 'flags': $value = array_change_key_case((array) $headers->flags); $value = array_filter($value); $value = array_keys($value); break; case 'from': case 'to': case 'cc': case 'bcc': case 'reply-to': $addresses = $headers->{$field == 'reply-to' ? 'replyto' : $field}; $addresses = rcube_mime::decode_address_list($addresses, null, true, $headers->charset); $value = array(); foreach ((array) $addresses as $addr) { $idx = count($value); if ($addr['mailto']) { $value[$idx]['address'] = $addr['mailto']; } if ($addr['name']) { $value[$idx]['name'] = $addr['name']; } } if ($field == 'from' && !empty($value)) { $value = $value[0]; } break; } // add the value to the result if ($value !== null && $value !== '' && (!is_array($value) || !empty($value))) { // make sure we have utf-8 here $value = rcube_charset::clean($value); $result[$field] = $value; } } // complete rcube_message object, we can set more props? if (!$is_header) { // @TODO } return $result; } } diff --git a/tests/API/Attachments.php b/tests/API/Attachments.php index 28ad08c..ceb3b3e 100644 --- a/tests/API/Attachments.php +++ b/tests/API/Attachments.php @@ -1,212 +1,232 @@ head('attachments/' . md5('INBOX') . '/6/2'); + self::$api->head('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/2'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing attachment - self::$api->head('attachments/' . md5('INBOX') . '/6/2345'); + self::$api->head('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/2345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); // test attachments of non-mail objects - self::$api->head('attachments/' . md5('Calendar') . '/100-100-100-100/3'); + self::$api->head('attachments/' . kolab_api_tests::folder_uid('Calendar') . '/100-100-100-100/3'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); } /** * Test attachment info */ function test_attachment_info() { - self::$api->get('attachments/' . md5('INBOX') . '/6/2'); + self::$api->get('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/2'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('2', $body['id']); $this->assertSame('text/plain', $body['mimetype']); $this->assertSame('test.txt', $body['filename']); $this->assertSame(4, $body['size']); // and non-existing attachment - self::$api->get('attachments/' . md5('INBOX') . '/6/2345'); + self::$api->get('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/2345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); // test attachments of kolab objects - self::$api->get('attachments/' . md5('Calendar') . '/100-100-100-100/3'); + self::$api->get('attachments/' . kolab_api_tests::folder_uid('Calendar') . '/100-100-100-100/3'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('3', $body['id']); $this->assertSame('image/jpeg', $body['mimetype']); $this->assertSame('photo-mini.jpg', $body['filename']); $this->assertSame('attachment', $body['disposition']); $this->assertSame(793, $body['size']); } /** * Test attachment body */ function test_attachment_get() { // mail attachment - self::$api->get('attachments/' . md5('INBOX') . '/6/3/get'); + self::$api->get('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/3/get'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame(793, strlen($body)); $this->assertSame('/9j/4AAQSkZJRgAB', substr(base64_encode($body), 0, 16)); // @TODO: headers // test attachments of kolab objects - self::$api->get('attachments/' . md5('Tasks') . '/10-10-10-10/3/get'); + self::$api->get('attachments/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10/3/get'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame(4, strlen($body)); $this->assertSame('test', $body); } /** * Test attachment create */ function test_attachment_create() { return; // @TODO $post = json_encode(array( 'filename' => 'test.txt', 'mimetype' => 'text/plain' )); - self::$api->post('attachments/' . md5('INBOX') . '/6', array(), $post); + self::$api->post('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['uid'])); // folder does not exists $post = json_encode(array( 'summary' => 'Test summary 2', )); - self::$api->post('attachments/' . md5('non-existing') . '/1234', array(), $post); + self::$api->post('attachments/' . kolab_api_tests::folder_uid('non-existing') . '/1234', array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( 'test' => 'Test 2', )); - self::$api->post('attachments/' . md5('INBOX') . '/6', array(), $post); + self::$api->post('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6', array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test attachment update */ function test_attachment_update() { return; // @TODO $post = json_encode(array( 'filename' => 'modified.txt', )); - self::$api->put('attachments/' . md5('INBOX') . '/6/2', array(), $post); + self::$api->put('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/2', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('attachments/' . md5('INBOX') . '/6/2'); + self::$api->get('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/2'); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('modified.txt', $body['filename']); } /** * Test attachment delete */ function test_attachment_delete() { -return; // @TODO // delete existing attachment - self::$api->delete('attachments/' . md5('INBOX') . '/6/2'); + self::$api->delete('attachments/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10/3'); + + $code = self::$api->response_code(); + $body = self::$api->response_body(); + + $this->assertEquals(204, $code); + $this->assertSame('', $body); + + // delete non-existing attachment in an existing object + self::$api->delete('attachments/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10/3'); + + $code = self::$api->response_code(); + $body = self::$api->response_body(); + + $this->assertEquals(404, $code); + $this->assertSame('', $body); +/* + @TODO: the same for e-mail + + // delete existing attachment + self::$api->delete('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/2'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing attachment - self::$api->delete('attachments/' . md5('INBOX') . '/6/2345'); + self::$api->delete('attachments/' . kolab_api_tests::folder_uid('INBOX') . '/6/2345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); +*/ } } diff --git a/tests/API/Contacts.php b/tests/API/Contacts.php index 1142218..0053048 100644 --- a/tests/API/Contacts.php +++ b/tests/API/Contacts.php @@ -1,187 +1,187 @@ get('folders/' . md5('Contacts') . '/objects'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Contacts') . '/objects'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('a-b-c-d', $body[0]['uid']); $this->assertSame('displname', $body[0]['fn']); } /** * Test contact existence */ function test_contact_exists() { - self::$api->head('contacts/' . md5('Contacts') . '/a-b-c-d'); + self::$api->head('contacts/' . kolab_api_tests::folder_uid('Contacts') . '/a-b-c-d'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing contact - self::$api->head('contacts/' . md5('Contacts') . '/12345'); + self::$api->head('contacts/' . kolab_api_tests::folder_uid('Contacts') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test contact info */ function test_contact_info() { - self::$api->get('contacts/' . md5('Contacts') . '/a-b-c-d'); + self::$api->get('contacts/' . kolab_api_tests::folder_uid('Contacts') . '/a-b-c-d'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('a-b-c-d', $body['uid']); $this->assertSame('displname', $body['fn']); + $this->assertSame(array('tag1'), $body['categories']); } /** * Test contact create */ function test_contact_create() { $post = json_encode(array( 'n' => array( 'surname' => 'lastname', ), 'note' => 'Test description', )); - self::$api->post('contacts/' . md5('Contacts'), array(), $post); + self::$api->post('contacts/' . kolab_api_tests::folder_uid('Contacts'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['uid'])); // folder does not exists $post = json_encode(array( 'n' => array( 'surname' => 'lastname', ), 'note' => 'Test description', )); - self::$api->post('contacts/' . md5('non-existing'), array(), $post); + self::$api->post('contacts/' . kolab_api_tests::folder_uid('non-existing'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( 'test' => 'Test summary 2', )); - self::$api->post('contacts/' . md5('Contacts'), array(), $post); + self::$api->post('contacts/' . kolab_api_tests::folder_uid('Contacts'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test contact update */ function test_contact_update() { $post = json_encode(array( 'note' => 'note1', )); - self::$api->put('contacts/' . md5('Contacts') . '/a-b-c-d', array(), $post); + self::$api->put('contacts/' . kolab_api_tests::folder_uid('Contacts') . '/a-b-c-d', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('contacts/' . md5('Contacts') . '/a-b-c-d'); + self::$api->get('contacts/' . kolab_api_tests::folder_uid('Contacts') . '/a-b-c-d'); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('note1', $body['note']); } /** * Test contact delete */ function test_contact_delete() { // delete existing contact - self::$api->delete('contacts/' . md5('Contacts') . '/a-b-c-d'); + self::$api->delete('contacts/' . kolab_api_tests::folder_uid('Contacts') . '/a-b-c-d'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing contact - self::$api->delete('contacts/' . md5('Contacts') . '/12345'); + self::$api->delete('contacts/' . kolab_api_tests::folder_uid('Contacts') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test counting task attachments */ function test_count_attachments() { - // @TODO + $this->markTestIncomplete('TODO'); } /** * Test listing task attachments */ function test_list_attachments() { - // @TODO + $this->markTestIncomplete('TODO'); } - } diff --git a/tests/API/Events.php b/tests/API/Events.php index af8573f..b6bfddd 100644 --- a/tests/API/Events.php +++ b/tests/API/Events.php @@ -1,217 +1,217 @@ get('folders/' . md5('Calendar') . '/objects'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Calendar') . '/objects'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('100-100-100-100', $body[0]['uid']); $this->assertSame('Summary', $body[0]['summary']); $this->assertSame('101-101-101-101', $body[1]['uid']); $this->assertSame('PUBLIC', $body[1]['class']); } /** * Test event existence */ function test_event_exists() { - self::$api->head('events/' . md5('Calendar') . '/100-100-100-100'); + self::$api->head('events/' . kolab_api_tests::folder_uid('Calendar') . '/100-100-100-100'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing event - self::$api->head('events/' . md5('Calendar') . '/12345'); + self::$api->head('events/' . kolab_api_tests::folder_uid('Calendar') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test event info */ function test_event_info() { - self::$api->get('events/' . md5('Calendar') . '/100-100-100-100'); + self::$api->get('events/' . kolab_api_tests::folder_uid('Calendar') . '/100-100-100-100'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('100-100-100-100', $body['uid']); $this->assertSame('Summary', $body['summary']); } /** * Test event create */ function test_event_create() { $post = json_encode(array( 'summary' => 'Test description', 'dtstart' => '2015-01-01', )); - self::$api->post('events/' . md5('Calendar'), array(), $post); + self::$api->post('events/' . kolab_api_tests::folder_uid('Calendar'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['uid'])); // folder does not exists $post = json_encode(array( 'summary' => 'Test description', 'dtstart' => '2015-01-01', )); - self::$api->post('events/' . md5('non-existing'), array(), $post); + self::$api->post('events/' . kolab_api_tests::folder_uid('non-existing'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( 'test' => 'Test summary 2', )); - self::$api->post('events/' . md5('Calendar'), array(), $post); + self::$api->post('events/' . kolab_api_tests::folder_uid('Calendar'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test event update */ function test_event_update() { // @TODO: test modification of all supported properties $post = json_encode(array( 'summary' => 'Modified summary (1)', 'dtstart' => '2015-01-01', )); - self::$api->put('events/' . md5('Calendar') . '/100-100-100-100', array(), $post); + self::$api->put('events/' . kolab_api_tests::folder_uid('Calendar') . '/100-100-100-100', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('events/' . md5('Calendar') . '/100-100-100-100'); + self::$api->get('events/' . kolab_api_tests::folder_uid('Calendar') . '/100-100-100-100'); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('Modified summary (1)', $body['summary']); } /** * Test counting event attachments */ function test_count_attachments() { - self::$api->head('events/' . md5('Calendar') . '/100-100-100-100/attachments'); + self::$api->head('events/' . kolab_api_tests::folder_uid('Calendar') . '/100-100-100-100/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-Count'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(1, (int) $count); - self::$api->head('events/' . md5('Calendar') . '/101-101-101-101/attachments'); + self::$api->head('events/' . kolab_api_tests::folder_uid('Calendar') . '/101-101-101-101/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-Count'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(0, (int) $count); } /** * Test listing event attachments */ function test_list_attachments() { - self::$api->get('events/' . md5('Calendar') . '/100-100-100-100/attachments'); + self::$api->get('events/' . kolab_api_tests::folder_uid('Calendar') . '/100-100-100-100/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertSame('3', $body[0]['id']); $this->assertSame('image/jpeg', $body[0]['mimetype']); $this->assertSame('photo-mini.jpg', $body[0]['filename']); $this->assertSame('attachment', $body[0]['disposition']); $this->assertSame(793, $body[0]['size']); } /** * Test event delete */ function test_event_delete() { // delete existing event - self::$api->delete('events/' . md5('Calendar') . '/101-101-101-101'); + self::$api->delete('events/' . kolab_api_tests::folder_uid('Calendar') . '/101-101-101-101'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing event - self::$api->delete('events/' . md5('Calendar') . '/12345'); + self::$api->delete('events/' . kolab_api_tests::folder_uid('Calendar') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } } diff --git a/tests/API/Folders.php b/tests/API/Folders.php index cfdb2de..1ce4c63 100644 --- a/tests/API/Folders.php +++ b/tests/API/Folders.php @@ -1,324 +1,324 @@ get('folders/test'); $code = self::$api->response_code(); $this->assertEquals(404, $code); // non-existing action - self::$api->get('folders/' . md5('INBOX') . '/test'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('INBOX') . '/test'); $code = self::$api->response_code(); $this->assertEquals(404, $code); // existing action and folder, but wrong method - self::$api->get('folders/' . md5('Mail-Test') . '/empty'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Mail-Test') . '/empty'); $code = self::$api->response_code(); $this->assertEquals(404, $code); } /** * Test listing all folders */ function test_folder_list_folders() { // get all folders self::$api->get('folders'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(15, $body); $this->assertSame('Calendar', $body[0]['fullpath']); $this->assertSame('event.default', $body[0]['type']); - $this->assertSame(md5('Calendar'), $body[0]['uid']); + $this->assertSame(kolab_api_tests::folder_uid('Calendar'), $body[0]['uid']); $this->assertNull($body[0]['parent']); // test listing subfolders of specified folder - self::$api->get('folders/' . md5('Calendar') . '/folders'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Calendar') . '/folders'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertSame('Calendar/Personal Calendar', $body[0]['fullpath']); - $this->assertSame(md5('Calendar'), $body[0]['parent']); + $this->assertSame(kolab_api_tests::folder_uid('Calendar'), $body[0]['parent']); // get all folders with properties filter self::$api->get('folders', array('properties' => 'uid')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body[0]); - $this->assertSame(md5('Calendar'), $body[0]['uid']); + $this->assertSame(kolab_api_tests::folder_uid('Calendar'), $body[0]['uid']); } /** * Test folder delete */ function test_folder_delete() { // delete existing folder - self::$api->delete('folders/' . md5('Mail-Test')); + self::$api->delete('folders/' . kolab_api_tests::folder_uid('Mail-Test')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing folder self::$api->delete('folders/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test folder existence */ function test_folder_exists() { - self::$api->head('folders/' . md5('INBOX')); + self::$api->head('folders/' . kolab_api_tests::folder_uid('INBOX')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing folder - deleted in test_folder_delete() - self::$api->head('folders/' . md5('Mail-Test')); + self::$api->head('folders/' . kolab_api_tests::folder_uid('Mail-Test')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test folder update */ function test_folder_update() { $post = json_encode(array( 'name' => 'Mail-Test22', 'type' => 'mail' )); - self::$api->put('folders/' . md5('Mail-Test2'), array(), $post); + self::$api->put('folders/' . kolab_api_tests::folder_uid('Mail-Test2'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // move into an existing folder $post = json_encode(array( 'name' => 'Trash', )); - self::$api->put('folders/' . md5('Mail-Test22'), array(), $post); + self::$api->put('folders/' . kolab_api_tests::folder_uid('Mail-Test22'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(500, $code); // change parent to an existing folder $post = json_encode(array( - 'parent' => md5('Trash'), + 'parent' => kolab_api_tests::folder_uid('Trash'), )); - self::$api->put('folders/' . md5('Mail-Test22'), array(), $post); + self::$api->put('folders/' . kolab_api_tests::folder_uid('Mail-Test22'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(204, $code); } /** * Test folder create */ function test_folder_create() { $post = json_encode(array( 'name' => 'Test-create', 'type' => 'mail' )); self::$api->post('folders', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(md5('Test-create'), $body['uid']); + $this->assertSame(kolab_api_tests::folder_uid('Test-create'), $body['uid']); // folder already exists $post = json_encode(array( 'name' => 'Test-create', )); self::$api->post('folders', array(), $post); $code = self::$api->response_code(); $this->assertEquals(500, $code); // create a subfolder $post = json_encode(array( 'name' => 'Test', - 'parent' => md5('Test-create'), + 'parent' => kolab_api_tests::folder_uid('Test-create'), 'type' => 'mail' )); self::$api->post('folders', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(md5('Test-create/Test'), $body['uid']); + $this->assertSame(kolab_api_tests::folder_uid('Test-create/Test'), $body['uid']); // parent folder does not exists $post = json_encode(array( 'name' => 'Test-create-2', 'parent' => '123456789', )); self::$api->post('folders', array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); } /** * Test folder info */ function test_folder_info() { - self::$api->get('folders/' . md5('INBOX')); + self::$api->get('folders/' . kolab_api_tests::folder_uid('INBOX')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('INBOX', $body['name']); - $this->assertSame(md5('INBOX'), $body['uid']); + $this->assertSame(kolab_api_tests::folder_uid('INBOX'), $body['uid']); } /** * Test folder create */ function test_folder_delete_objects() { $post = json_encode(array('10')); - self::$api->post('folders/' . md5('Notes') . '/deleteobjects', array(), $post); + self::$api->post('folders/' . kolab_api_tests::folder_uid('Notes') . '/deleteobjects', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); } /** * Test folder create */ function test_folder_empty() { - self::$api->post('folders/' . md5('Trash') . '/empty'); + self::$api->post('folders/' . kolab_api_tests::folder_uid('Trash') . '/empty'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); } /** * Test listing folder content */ function test_folder_list_objects() { - self::$api->get('folders/' . md5('Calendar/Personal Calendar') . '/objects'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Calendar/Personal Calendar') . '/objects'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(array(), $body); // get all objects with properties filter - self::$api->get('folders/' . md5('Notes') . '/objects', array('properties' => 'uid')); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Notes') . '/objects', array('properties' => 'uid')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body[0]); $this->assertSame('1-1-1-1', $body[0]['uid']); } /** * Test counting folder content */ function test_folder_count_objects() { - self::$api->head('folders/' . md5('INBOX') . '/objects'); + self::$api->head('folders/' . kolab_api_tests::folder_uid('INBOX') . '/objects'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-Count'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(4, (int) $count); // folder emptied in test_folder_empty() - self::$api->head('folders/' . md5('Trash') . '/objects'); + self::$api->head('folders/' . kolab_api_tests::folder_uid('Trash') . '/objects'); $count = self::$api->response_header('X-Count'); $this->assertSame(0, (int) $count); // one item removed in test_folder_delete_objects() - self::$api->head('folders/' . md5('Notes') . '/objects'); + self::$api->head('folders/' . kolab_api_tests::folder_uid('Notes') . '/objects'); $count = self::$api->response_header('X-Count'); $this->assertSame(2, (int) $count); } } diff --git a/tests/API/Mails.php b/tests/API/Mails.php index e642163..7143d3c 100644 --- a/tests/API/Mails.php +++ b/tests/API/Mails.php @@ -1,244 +1,245 @@ get('folders/' . md5('INBOX') . '/objects'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('INBOX') . '/objects'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(4, count($body)); $this->assertSame('1', $body[0]['uid']); $this->assertSame('"test" wurde aktualisiert', $body[0]['subject']); $this->assertSame('2', $body[1]['uid']); $this->assertSame('Re: dsda', $body[1]['subject']); } /** * Test mail existence check */ function test_mail_exists() { - self::$api->head('mails/' . md5('INBOX') . '/1'); + self::$api->head('mails/' . kolab_api_tests::folder_uid('INBOX') . '/1'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing mail - self::$api->head('mails/' . md5('INBOX') . '/12345'); + self::$api->head('mails/' . kolab_api_tests::folder_uid('INBOX') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test mail info */ function test_mail_info() { - self::$api->get('mails/' . md5('INBOX') . '/1'); + self::$api->get('mails/' . kolab_api_tests::folder_uid('INBOX') . '/1'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('1', $body['uid']); $this->assertSame('"test" wurde aktualisiert', $body['subject']); $this->assertSame(624, $body['size']); - self::$api->get('mails/' . md5('INBOX') . '/6'); + self::$api->get('mails/' . kolab_api_tests::folder_uid('INBOX') . '/6'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('6', $body['uid']); } /** * Test mail create */ function test_mail_create() { return; // @TODO $post = json_encode(array( 'summary' => 'Test summary', 'description' => 'Test description' )); - self::$api->post('mails/' . md5('INBOX'), array(), $post); + self::$api->post('mails/' . kolab_api_tests::folder_uid('INBOX'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['uid'])); // folder does not exists $post = json_encode(array( 'summary' => 'Test summary 2', )); - self::$api->post('mails/' . md5('non-existing'), array(), $post); + self::$api->post('mails/' . kolab_api_tests::folder_uid('non-existing'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( 'test' => 'Test summary 2', )); - self::$api->post('mails/' . md5('INBOX'), array(), $post); + self::$api->post('mails/' . kolab_api_tests::folder_uid('INBOX'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test mail update */ function test_mail_update() { return; // @TODO $post = json_encode(array( 'summary' => 'Modified summary', 'description' => 'Modified description' )); - self::$api->put('mails/' . md5('INBOX') . '/1', array(), $post); + self::$api->put('mails/' . kolab_api_tests::folder_uid('INBOX') . '/1', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('mails/' . md5('INBOX') . '/1'); + self::$api->get('mails/' . kolab_api_tests::folder_uid('INBOX') . '/1'); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('Modified summary', $body['summary']); $this->assertSame('Modified description', $body['description']); } /** * Test mail submit */ function test_mail_submit() { // @TODO + $this->markTestIncomplete('TODO'); } /** * Test mail delete */ function test_mail_delete() { // delete existing mail - self::$api->delete('mails/' . md5('INBOX') . '/1'); + self::$api->delete('mails/' . kolab_api_tests::folder_uid('INBOX') . '/1'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing mail - self::$api->delete('mails/' . md5('INBOX') . '/12345'); + self::$api->delete('mails/' . kolab_api_tests::folder_uid('INBOX') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test counting mail attachments */ function test_count_attachments() { - self::$api->head('mails/' . md5('INBOX') . '/2/attachments'); + self::$api->head('mails/' . kolab_api_tests::folder_uid('INBOX') . '/2/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-Count'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(0, (int) $count); - self::$api->head('mails/' . md5('INBOX') . '/6/attachments'); + self::$api->head('mails/' . kolab_api_tests::folder_uid('INBOX') . '/6/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-Count'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(2, (int) $count); } /** * Test listing mail attachments */ function test_list_attachments() { - self::$api->get('mails/' . md5('INBOX') . '/2/attachments'); + self::$api->get('mails/' . kolab_api_tests::folder_uid('INBOX') . '/2/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(array(), $body); - self::$api->get('mails/' . md5('INBOX') . '/6/attachments'); + self::$api->get('mails/' . kolab_api_tests::folder_uid('INBOX') . '/6/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(2, $body); $this->assertSame('2', $body[0]['id']); $this->assertSame('text/plain', $body[0]['mimetype']); $this->assertSame('test.txt', $body[0]['filename']); $this->assertSame('attachment', $body[0]['disposition']); $this->assertSame(4, $body[0]['size']); } } diff --git a/tests/API/Notes.php b/tests/API/Notes.php index d75ce49..943b9d9 100644 --- a/tests/API/Notes.php +++ b/tests/API/Notes.php @@ -1,212 +1,213 @@ get('folders/' . md5('Notes') . '/objects'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Notes') . '/objects'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(2, count($body)); $this->assertSame('1-1-1-1', $body[0]['uid']); $this->assertSame('test', $body[0]['summary']); $this->assertSame('2-2-2-2', $body[1]['uid']); $this->assertSame('wwww', $body[1]['summary']); } /** * Test note existence */ function test_note_exists() { - self::$api->head('notes/' . md5('Notes') . '/1-1-1-1'); + self::$api->head('notes/' . kolab_api_tests::folder_uid('Notes') . '/1-1-1-1'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing note - self::$api->head('notes/' . md5('Notes') . '/12345'); + self::$api->head('notes/' . kolab_api_tests::folder_uid('Notes') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test note info */ function test_note_info() { - self::$api->get('notes/' . md5('Notes') . '/1-1-1-1'); + self::$api->get('notes/' . kolab_api_tests::folder_uid('Notes') . '/1-1-1-1'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('1-1-1-1', $body['uid']); $this->assertSame('test', $body['summary']); } /** * Test note create */ function test_note_create() { $post = json_encode(array( 'summary' => 'Test summary', 'description' => 'Test description' )); - self::$api->post('notes/' . md5('Notes'), array(), $post); + self::$api->post('notes/' . kolab_api_tests::folder_uid('Notes'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['uid'])); // folder does not exists $post = json_encode(array( 'summary' => 'Test summary 2', )); - self::$api->post('notes/' . md5('non-existing'), array(), $post); + self::$api->post('notes/' . kolab_api_tests::folder_uid('non-existing'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( 'test' => 'Test summary 2', )); - self::$api->post('notes/' . md5('Notes'), array(), $post); + self::$api->post('notes/' . kolab_api_tests::folder_uid('Notes'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test note update */ function test_note_update() { $post = json_encode(array( 'summary' => 'Modified summary', 'description' => 'Modified description', 'classification' => 'PRIVATE', 'categories' => array('test'), 'unknown' => 'test' )); - self::$api->put('notes/' . md5('Notes') . '/1-1-1-1', array(), $post); + + self::$api->put('notes/' . kolab_api_tests::folder_uid('Notes') . '/1-1-1-1', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('notes/' . md5('Notes') . '/1-1-1-1'); + self::$api->get('notes/' . kolab_api_tests::folder_uid('Notes') . '/1-1-1-1'); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('Modified summary', $body['summary']); $this->assertSame('Modified description', $body['description']); $this->assertSame('PRIVATE', $body['classification']); $this->assertSame(array('test'), $body['categories']); $this->assertSame(null, $body['unknown']); // test unsetting some data $post = json_encode(array( - 'description' => null, - 'categories' => null, + 'description' => null, + 'categories' => null, )); - self::$api->put('notes/' . md5('Notes') . '/1-1-1-1', array(), $post); + self::$api->put('notes/' . kolab_api_tests::folder_uid('Notes') . '/1-1-1-1', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('notes/' . md5('Notes') . '/1-1-1-1'); + self::$api->get('notes/' . kolab_api_tests::folder_uid('Notes') . '/1-1-1-1'); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame(null, $body['description']); $this->assertSame(null, $body['categories']); } /** * Test note delete */ function test_note_delete() { // delete existing note - self::$api->delete('notes/' . md5('Notes') . '/1-1-1-1'); + self::$api->delete('notes/' . kolab_api_tests::folder_uid('Notes') . '/1-1-1-1'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing note - self::$api->delete('notes/' . md5('Notes') . '/12345'); + self::$api->delete('notes/' . kolab_api_tests::folder_uid('Notes') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test counting task attachments */ function test_count_attachments() { // @TODO } /** * Test listing task attachments */ function test_list_attachments() { // @TODO } } diff --git a/tests/API/Tasks.php b/tests/API/Tasks.php index 2cb26b6..ade9198 100644 --- a/tests/API/Tasks.php +++ b/tests/API/Tasks.php @@ -1,234 +1,234 @@ get('folders/' . md5('Tasks') . '/objects'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Tasks') . '/objects'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(2, count($body)); $this->assertSame('10-10-10-10', $body[0]['uid']); $this->assertSame('task title', $body[0]['summary']); $this->assertSame('20-20-20-20', $body[1]['uid']); $this->assertSame('task', $body[1]['summary']); } /** * Test task existence */ function test_task_exists() { - self::$api->head('tasks/' . md5('Tasks') . '/10-10-10-10'); + self::$api->head('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing task - self::$api->head('tasks/' . md5('Tasks') . '/12345'); + self::$api->head('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test task info */ function test_task_info() { - self::$api->get('tasks/' . md5('Tasks') . '/10-10-10-10'); + self::$api->get('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('10-10-10-10', $body['uid']); $this->assertSame('task title', $body['summary']); } /** * Test task create */ function test_task_create() { $post = json_encode(array( 'summary' => 'Test summary', 'description' => 'Test description' )); - self::$api->post('tasks/' . md5('Tasks'), array(), $post); + self::$api->post('tasks/' . kolab_api_tests::folder_uid('Tasks'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['uid'])); // folder does not exists $post = json_encode(array( 'summary' => 'Test summary 2', )); - self::$api->post('tasks/' . md5('non-existing'), array(), $post); + self::$api->post('tasks/' . kolab_api_tests::folder_uid('non-existing'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( 'test' => 'Test summary 2', )); - self::$api->post('tasks/' . md5('Tasks'), array(), $post); + self::$api->post('tasks/' . kolab_api_tests::folder_uid('Tasks'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test task update */ function test_task_update() { $post = json_encode(array( 'summary' => 'modified summary', 'description' => 'modified description', 'class' => 'PRIVATE', 'dtstart' => '2014-01-10', )); - self::$api->put('tasks/' . md5('Tasks') . '/10-10-10-10', array(), $post); + self::$api->put('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('tasks/' . md5('Tasks') . '/10-10-10-10'); + self::$api->get('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10'); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('modified summary', $body['summary']); $this->assertSame('modified description', $body['description']); $this->assertSame('PRIVATE', $body['class']); // test unsetting some properties $post = json_encode(array( 'due' => null, 'related-to' => null, 'location' => null, 'unknown' => 'test', )); - self::$api->put('tasks/' . md5('Tasks') . '/10-10-10-10', array(), $post); + self::$api->put('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('tasks/' . md5('Tasks') . '/10-10-10-10'); + self::$api->get('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10'); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('2014-01-10', $body['dtstart']); $this->assertSame(null, $body['due']); $this->assertSame(null, $body['related-to']); $this->assertSame(null, $body['location']); $this->assertSame(null, $body['unknown']); } /** * Test task delete */ function test_task_delete() { // delete existing task - self::$api->delete('tasks/' . md5('Tasks') . '/20-20-20-20'); + self::$api->delete('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/20-20-20-20'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing task - self::$api->delete('tasks/' . md5('Tasks') . '/12345'); + self::$api->delete('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test counting task attachments */ function test_count_attachments() { - self::$api->head('tasks/' . md5('Tasks') . '/10-10-10-10/attachments'); + self::$api->head('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-Count'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(1, (int) $count); } /** * Test listing task attachments */ function test_list_attachments() { - self::$api->get('tasks/' . md5('Tasks') . '/10-10-10-10/attachments'); + self::$api->get('tasks/' . kolab_api_tests::folder_uid('Tasks') . '/10-10-10-10/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertSame('3', $body[0]['id']); $this->assertSame('text/plain', $body[0]['mimetype']); $this->assertSame('test.txt', $body[0]['filename']); $this->assertSame('attachment', $body[0]['disposition']); $this->assertSame(4, $body[0]['size']); } } diff --git a/tests/Mapistore/Attachments.php b/tests/Mapistore/Attachments.php index 8e56f33..c0d4003 100644 --- a/tests/Mapistore/Attachments.php +++ b/tests/Mapistore/Attachments.php @@ -1,122 +1,138 @@ head('attachments/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), 6, 2)); + self::$api->head('attachments/' . kolab_api_tests::mapi_uid('INBOX', true, 6, 2)); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing attachment - self::$api->head('attachments/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), 6, 2345)); + self::$api->head('attachments/' . kolab_api_tests::mapi_uid('INBOX', true, 6, 2345)); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); // test attachments of non-mail objects - self::$api->head('attachments/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100', 3)); + self::$api->head('attachments/' . kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100', 3)); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); } /** * Test attachment info */ function test_attachment_info() { - self::$api->get('attachments/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), 6, 2)); + self::$api->get('attachments/' . kolab_api_tests::mapi_uid('INBOX', true, 6, 2)); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('INBOX'), 6, 2), $body['id']); + $this->assertSame(kolab_api_tests::mapi_uid('INBOX', true, 6, 2), $body['id']); $this->assertSame('text/plain', $body['PidTagAttachMimeTag']); $this->assertSame('test.txt', $body['PidTagDisplayName']); $this->assertSame(4, $body['PidTagAttachSize']); $this->assertSame(1, $body['PidTagAttachMethod']); $this->assertSame('test', base64_decode($body['PidTagAttachDataBinary'])); // and non-existing attachment - self::$api->get('attachments/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), 6, 2345)); + self::$api->get('attachments/' . kolab_api_tests::mapi_uid('INBOX', true, 6, 2345)); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); // test attachments of kolab objects - self::$api->get('attachments/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100', 3)); + self::$api->get('attachments/' . kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100', 3)); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100', 3), $body['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100', 3), $body['id']); $this->assertSame('image/jpeg', $body['PidTagAttachMimeTag']); $this->assertSame('photo-mini.jpg', $body['PidTagDisplayName']); $this->assertSame(793, $body['PidTagAttachSize']); $this->assertSame(1, $body['PidTagAttachMethod']); $this->assertSame('/9j/4AAQSkZJRgAB', substr($body['PidTagAttachDataBinary'], 0, 16)); } /** * Test attachment create */ function test_attachment_create() { -return; // @TODO + $this->markTestIncomplete('TODO'); } /** * Test attachment update */ function test_attachment_update() { -return; // @TODO + $this->markTestIncomplete('TODO'); } /** * Test attachment delete */ function test_attachment_delete() { -return; // @TODO + // delete existing attachment + self::$api->delete('attachments/' . kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10', '3')); + + $code = self::$api->response_code(); + $body = self::$api->response_body(); + + $this->assertEquals(204, $code); + $this->assertSame('', $body); + + // delete non-existing attachment in an existing object + self::$api->delete('attachments/' . kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10', '3')); + + $code = self::$api->response_code(); + $body = self::$api->response_body(); + + $this->assertEquals(404, $code); + $this->assertSame('', $body); } } diff --git a/tests/Mapistore/Contacts.php b/tests/Mapistore/Contacts.php index d31cf00..19658c2 100644 --- a/tests/Mapistore/Contacts.php +++ b/tests/Mapistore/Contacts.php @@ -1,231 +1,231 @@ get('folders/' . md5('Contacts') . '/messages'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Contacts') . '/messages'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d'), $body[0]['id']); - $this->assertSame(md5('Contacts'), $body[0]['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Contacts', true, 'a-b-c-d'), $body[0]['id']); + $this->assertSame(kolab_api_tests::folder_uid('Contacts'), $body[0]['parent_id']); $this->assertSame('contacts', $body[0]['collection']); $this->assertSame('IPM.Contact', $body[0]['PidTagMessageClass']); $this->assertSame('displname', $body[0]['PidTagDisplayName']); } /** * Test contact existence */ function test_contact_exists() { - self::$api->head('contacts/' . kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d')); + self::$api->head('contacts/' . kolab_api_tests::mapi_uid('Contacts', true, 'a-b-c-d')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing contact - self::$api->get('contacts/' . kolab_api_filter_mapistore::uid_encode(md5('Contacts'), '12345')); + self::$api->get('contacts/' . kolab_api_tests::mapi_uid('Contacts', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test contact info */ function test_contact_info() { - self::$api->get('contacts/' . kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d')); + self::$api->get('contacts/' . kolab_api_tests::mapi_uid('Contacts', true, 'a-b-c-d')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d'), $body['id']); - $this->assertSame(md5('Contacts'), $body['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Contacts', true, 'a-b-c-d'), $body['id']); + $this->assertSame(kolab_api_tests::folder_uid('Contacts'), $body['parent_id']); $this->assertSame('contacts', $body['collection']); $this->assertSame('IPM.Contact', $body['PidTagMessageClass']); $this->assertSame('displname', $body['PidTagDisplayName']); } /** * Test contact create */ function test_contact_create() { $post = json_encode(array( - 'parent_id' => md5('Contacts'), + 'parent_id' => kolab_api_tests::folder_uid('Contacts'), 'PidTagSurname' => 'lastname', 'PidTagTitle' => 'Test title', )); self::$api->post('contacts', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['id'])); // folder does not exists $post = json_encode(array( - 'parent_id' => md5('non-existing'), + 'parent_id' => kolab_api_tests::folder_uid('non-existing'), 'PidTagSurname' => 'lastname', 'PidTagTitle' => 'Test title', )); self::$api->post('contacts', array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( - 'parent_id' => md5('Contacts'), + 'parent_id' => kolab_api_tests::folder_uid('Contacts'), 'test' => 'Test summary 2', )); self::$api->post('contacts', array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test contact update */ function test_contact_update() { // @TODO: most of this should probably be in unit-tests not functional-tests $post = array( 'PidTagTitle' => 'Title', 'PidTagNickname' => 'Nickname', 'PidTagDisplayName' => 'DisplayName', 'PidTagSurname' => 'Surname', 'PidTagGivenName' => 'GivenName', 'PidTagMiddleName' => 'MiddleName', 'PidTagDisplayNamePrefix' => 'Prefix', 'PidTagGeneration' => 'Generation', 'PidTagBody' => 'Body', 'PidLidFreeBusyLocation' => 'FreeBusyLocation', 'PidTagCompanyName' => 'CompanyName', 'PidTagDepartmentName' => 'Department', 'PidTagProfession' => 'Profession', 'PidTagManagerName' => 'Manager', 'PidTagAssistant' => 'Assistant', 'PidTagPersonalHomePage' => 'HomePage', 'PidTagOtherAddressStreet' => 'OtherStreet', 'PidTagOtherAddressCity' => 'OtherCity', 'PidTagOtherAddressStateOrProvince' => 'OtherState', 'PidTagOtherAddressPostalCode' => 'OtherCode', 'PidTagOtherAddressCountry' => 'OtherCountry', // 'PidTagOtherAddressPostOfficeBox' => 'OtherBox', 'PidTagHomeAddressStreet' => 'HomeStreet', 'PidTagHomeAddressCity' => 'HomeCity', 'PidTagHomeAddressStateOrProvince' => 'HomeState', 'PidTagHomeAddressPostalCode' => 'HomeCode', 'PidTagHomeAddressCountry' => 'HomeCountry', // 'PidTagHomeAddressPostOfficeBox' => 'HomeBox', 'PidLidWorkAddressStreet' => 'WorkStreet', 'PidLidWorkAddressCity' => 'WorkCity', 'PidLidWorkAddressState' => 'WorkState', 'PidLidWorkAddressPostalCode' => 'WorkCode', 'PidLidWorkAddressCountry' => 'WorkCountry', // 'PidLidWorkAddressPostOfficeBox' => 'WorkBox', 'PidTagGender' => 1, 'PidTagSpouseName' => 'Spouse', 'PidTagChildrensNames' => array('child'), 'PidTagHomeTelephoneNumber' => 'HomeNumber', 'PidTagBusinessTelephoneNumber' => 'BusinessNumber', 'PidTagHomeFaxNumber' => 'HomeFax', 'PidTagBusinessFaxNumber' => 'BusinessFax', 'PidTagMobileTelephoneNumber' => 'Mobile', 'PidTagPagerTelephoneNumber' => 'Pager', 'PidTagCarTelephoneNumber' => 'Car', 'PidTagOtherTelephoneNumber' => 'OtherNumber', 'PidLidInstantMessagingAddress' => 'IM', 'PidLidEmail1EmailAddress' => 'email1@domain.tld', 'PidLidEmail2EmailAddress' => 'email1@domain.tld', 'PidLidEmail3EmailAddress' => 'email1@domain.tld', 'PidTagUserX509Certificate' => base64_encode('Certificate'), ); - self::$api->put('contacts/' . kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d'), + self::$api->put('contacts/' . kolab_api_tests::mapi_uid('Contacts', true, 'a-b-c-d'), array(), json_encode($post)); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('contacts/' . kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d')); + self::$api->get('contacts/' . kolab_api_tests::mapi_uid('Contacts', true, 'a-b-c-d')); $body = self::$api->response_body(); $body = json_decode($body, true); foreach ($post as $idx => $value) { $this->assertSame($value, $body[$idx], "Test for update of $idx"); } } /** * Test contact delete */ function test_contact_delete() { // delete existing contact - self::$api->delete('contacts/' . kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d')); + self::$api->delete('contacts/' . kolab_api_tests::mapi_uid('Contacts', true, 'a-b-c-d')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing contact - self::$api->get('contacts/' . kolab_api_filter_mapistore::uid_encode(md5('Contacts'), '12345')); + self::$api->get('contacts/' . kolab_api_tests::mapi_uid('Contacts', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } } diff --git a/tests/Mapistore/Events.php b/tests/Mapistore/Events.php index 00c7d73..aef15a4 100644 --- a/tests/Mapistore/Events.php +++ b/tests/Mapistore/Events.php @@ -1,227 +1,226 @@ get('folders/' . md5('Calendar') . '/messages'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Calendar') . '/messages'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100'), $body[0]['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100'), $body[0]['id']); $this->assertSame('Summary', $body[0]['PidTagSubject']); $this->assertSame('Description', $body[0]['PidTagBody']); $this->assertSame('calendars', $body[0]['collection']); $this->assertSame('IPM.Appointment', $body[0]['PidTagMessageClass']); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '101-101-101-101'), $body[1]['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Calendar', true, '101-101-101-101'), $body[1]['id']); $this->assertSame(0, $body[1]['PidTagSensitivity']); $this->assertSame('calendars', $body[1]['collection']); $this->assertSame('IPM.Appointment', $body[1]['PidTagMessageClass']); } /** * Test event existence */ function test_event_exists() { - self::$api->head('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100')); + self::$api->head('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing event - self::$api->head('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '12345')); + self::$api->head('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test event info */ function test_event_info() { - self::$api->get('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100')); + self::$api->get('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100'), $body['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100'), $body['id']); $this->assertSame('Summary', $body['PidTagSubject']); $this->assertSame('calendars', $body['collection']); $this->assertSame('IPM.Appointment', $body['PidTagMessageClass']); } /** * Test event create */ function test_event_create() { $post = json_encode(array( - 'parent_id' => md5('Calendar'), + 'parent_id' => kolab_api_tests::folder_uid('Calendar'), 'PidTagSubject' => 'Test summary', 'PidLidAppointmentStartWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-01-01'), )); self::$api->post('calendars', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['id'])); // folder does not exists $post = json_encode(array( 'parent_id' => md5('non-existing'), 'PidTagSubject' => 'Test summary', 'PidLidAppointmentStartWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-01-01'), )); self::$api->post('calendars', array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( - 'parent_id' => md5('Calendar'), + 'parent_id' => kolab_api_tests::folder_uid('Calendar'), 'test' => 'Test summary 2', )); self::$api->post('calendars', array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test event update */ function test_event_update() { // @TODO: test modification of all supported properties $post = json_encode(array( 'PidTagSubject' => 'Modified subject (1)', 'PidLidAppointmentStartWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-01-01'), )); - self::$api->put('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100'), array(), $post); + self::$api->put('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100')); + self::$api->get('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100')); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('Modified subject (1)', $body['PidTagSubject']); } - /** - * Test event delete - */ - function test_event_delete() - { - // delete existing event - self::$api->delete('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '101-101-101-101')); - - $code = self::$api->response_code(); - $body = self::$api->response_body(); - - $this->assertEquals(204, $code); - $this->assertSame('', $body); - - // and non-existing event - self::$api->delete('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '12345')); - - $code = self::$api->response_code(); - $body = self::$api->response_body(); - - $this->assertEquals(404, $code); - $this->assertSame('', $body); - } - /** * Test counting event attachments */ function test_count_attachments() { - self::$api->head('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100') . '/attachments'); + self::$api->head('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(1, (int) $count); -/* - self::$api->head('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '101-101-101-101') . '/attachments'); + + self::$api->head('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '101-101-101-101') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(0, (int) $count); -*/ } /** * Test listing event attachments */ function test_list_attachments() { - self::$api->get('calendars/' . kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100') . '/attachments'); + self::$api->get('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100', '3'), $body[0]['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Calendar', true, '100-100-100-100', '3'), $body[0]['id']); $this->assertSame('image/jpeg', $body[0]['PidTagAttachMimeTag']); $this->assertSame('photo-mini.jpg', $body[0]['PidTagDisplayName']); $this->assertSame(793, $body[0]['PidTagAttachSize']); } + + /** + * Test event delete + */ + function test_event_delete() + { + // delete existing event + self::$api->delete('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '101-101-101-101')); + + $code = self::$api->response_code(); + $body = self::$api->response_body(); + + $this->assertEquals(204, $code); + $this->assertSame('', $body); + + // and non-existing event + self::$api->delete('calendars/' . kolab_api_tests::mapi_uid('Calendar', true, '12345')); + + $code = self::$api->response_code(); + $body = self::$api->response_body(); + + $this->assertEquals(404, $code); + $this->assertSame('', $body); + } } diff --git a/tests/Mapistore/Folders.php b/tests/Mapistore/Folders.php index d1cee06..b04be3b 100644 --- a/tests/Mapistore/Folders.php +++ b/tests/Mapistore/Folders.php @@ -1,297 +1,297 @@ get('folders/1/folders'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(12, $body); - $this->assertSame(md5('Calendar'), $body[0]['id']); - $this->assertSame(md5('Calendar'), $body[1]['parent_id']); + $this->assertSame(kolab_api_tests::folder_uid('Calendar'), $body[0]['id']); + $this->assertSame(kolab_api_tests::folder_uid('Calendar'), $body[1]['parent_id']); $this->assertNull($body[0]['parent_id']); $this->assertSame('IPF.Appointment', $body[0]['PidTagContainerClass']); $this->assertSame('IPF.Task', $body[10]['PidTagContainerClass']); // test listing subfolders of specified folder - self::$api->get('folders/' . md5('Calendar') . '/folders'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Calendar') . '/folders'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); - $this->assertSame(md5('Calendar'), $body[0]['parent_id']); + $this->assertSame(kolab_api_tests::folder_uid('Calendar'), $body[0]['parent_id']); // get all folders with properties filter self::$api->get('folders/1/folders', array('properties' => 'id')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(array('id' => md5('Calendar')), $body[0]); + $this->assertSame(array('id' => kolab_api_tests::folder_uid('Calendar')), $body[0]); } /** * Test folder delete */ function test_folder_delete() { // delete existing folder - self::$api->delete('folders/' . md5('Mail-Test')); + self::$api->delete('folders/' . kolab_api_tests::folder_uid('Mail-Test')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing folder self::$api->get('folders/12345'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test folder existence */ function test_folder_exists() { - self::$api->head('folders/' . md5('INBOX')); + self::$api->head('folders/' . kolab_api_tests::folder_uid('INBOX')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing folder - deleted in test_folder_delete() - self::$api->get('folders/' . md5('Mail-Test')); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Mail-Test')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test folder update */ function test_folder_update() { $post = json_encode(array( 'PidTagDisplayName' => 'Mail-Test22', )); - self::$api->put('folders/' . md5('Mail-Test2'), array(), $post); + self::$api->put('folders/' . kolab_api_tests::folder_uid('Mail-Test2'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // move into an existing folder $post = json_encode(array( 'PidTagDisplayName' => 'Trash', )); - self::$api->put('folders/' . md5('Mail-Test22'), array(), $post); + self::$api->put('folders/' . kolab_api_tests::folder_uid('Mail-Test22'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(500, $code); // change parent to an existing folder $post = json_encode(array( - 'parent_id' => md5('Trash'), + 'parent_id' => kolab_api_tests::folder_uid('Trash'), )); - self::$api->put('folders/' . md5('Mail-Test22'), array(), $post); + self::$api->put('folders/' . kolab_api_tests::folder_uid('Mail-Test22'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(204, $code); } /** * Test folder create */ function test_folder_create() { $post = json_encode(array( 'PidTagDisplayName' => 'Test-create', )); self::$api->post('folders', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(md5('Test-create'), $body['id']); + $this->assertSame(kolab_api_tests::folder_uid('Test-create'), $body['id']); // folder already exists $post = json_encode(array( 'PidTagDisplayName' => 'Test-create', )); self::$api->post('folders', array(), $post); $code = self::$api->response_code(); $this->assertEquals(500, $code); // create a subfolder $post = json_encode(array( 'PidTagDisplayName' => 'Test', - 'parent_id' => md5('Test-create'), + 'parent_id' => kolab_api_tests::folder_uid('Test-create'), )); self::$api->post('folders', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(md5('Test-create/Test'), $body['id']); + $this->assertSame(kolab_api_tests::folder_uid('Test-create/Test'), $body['id']); // parent folder does not exists $post = json_encode(array( 'PidTagDisplayName' => 'Test-create-2', 'parent_id' => '123456789', )); self::$api->post('folders', array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); } /** * Test folder info */ function test_folder_info() { - self::$api->get('folders/' . md5('INBOX')); + self::$api->get('folders/' . kolab_api_tests::folder_uid('INBOX')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame('INBOX', $body['PidTagDisplayName']); - $this->assertSame(md5('INBOX'), $body['id']); + $this->assertSame(kolab_api_tests::folder_uid('INBOX'), $body['id']); } /** * Test folder create */ function test_folder_delete_objects() { $post = json_encode(array(array('id' => '10'))); - self::$api->post('folders/' . md5('Notes') . '/deletemessages', array(), $post); + self::$api->post('folders/' . kolab_api_tests::folder_uid('Notes') . '/deletemessages', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); } /** * Test folder create */ function test_folder_empty() { - self::$api->post('folders/' . md5('Trash') . '/empty'); + self::$api->post('folders/' . kolab_api_tests::folder_uid('Trash') . '/empty'); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); } /** * Test listing folder content */ function test_folder_list_objects() { - self::$api->get('folders/' . md5('Calendar/Personal Calendar') . '/messages'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Calendar/Personal Calendar') . '/messages'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(array(), $body); // get all objects with properties filter - self::$api->get('folders/' . md5('Notes') . '/messages', array('properties' => 'id,collection')); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Notes') . '/messages', array('properties' => 'id,collection')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(2, $body[0]); $this->assertTrue(!empty($body[0]['id'])); $this->assertSame('notes', $body[0]['collection']); } /** * Test counting folder content */ function test_folder_count_objects() { - self::$api->head('folders/' . md5('INBOX') . '/messages'); + self::$api->head('folders/' . kolab_api_tests::folder_uid('INBOX') . '/messages'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(4, (int) $count); // folder emptied in test_folder_empty() - self::$api->head('folders/' . md5('Trash') . '/mssages'); + self::$api->head('folders/' . kolab_api_tests::folder_uid('Trash') . '/mssages'); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertSame(0, (int) $count); // one item removed in test_folder_delete_objects() - self::$api->head('folders/' . md5('Notes') . '/messages'); + self::$api->head('folders/' . kolab_api_tests::folder_uid('Notes') . '/messages'); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertSame(2, (int) $count); } } diff --git a/tests/Mapistore/Info.php b/tests/Mapistore/Info.php index a1e695e..178ff88 100644 --- a/tests/Mapistore/Info.php +++ b/tests/Mapistore/Info.php @@ -1,53 +1,51 @@ get('info'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - - // @TODO $this->assertSame(kolab_api::APP_NAME, $body['name']); $this->assertSame(kolab_api::VERSION, $body['version']); } /** * Test non-existing request */ function test_nonexisting() { self::$api->post('info'); $code = self::$api->response_code(); $this->assertEquals(404, $code); } } diff --git a/tests/Mapistore/Mails.php b/tests/Mapistore/Mails.php index 3829966..ed9032e 100644 --- a/tests/Mapistore/Mails.php +++ b/tests/Mapistore/Mails.php @@ -1,255 +1,257 @@ get('folders/' . md5('INBOX') . '/messages'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('INBOX') . '/messages'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(4, count($body)); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1'), $body[0]['id']); - $this->assertSame(md5('INBOX'), $body[0]['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('INBOX', true, '1'), $body[0]['id']); + $this->assertSame(kolab_api_tests::folder_uid('INBOX'), $body[0]['parent_id']); $this->assertSame('mails', $body[0]['collection']); $this->assertSame('IPM.Note', $body[0]['PidTagMessageClass']); $this->assertSame('"test" wurde aktualisiert', $body[0]['PidTagSubject']); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '2'), $body[1]['id']); - $this->assertSame(md5('INBOX'), $body[1]['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('INBOX', true, '2'), $body[1]['id']); + $this->assertSame(kolab_api_tests::folder_uid('INBOX'), $body[1]['parent_id']); $this->assertSame('IPM.Note', $body[1]['PidTagMessageClass']); $this->assertSame('Re: dsda', $body[1]['PidTagSubject']); // get all messages with properties filter - self::$api->get('folders/' . md5('INBOX') . '/messages', array('properties' => 'id')); + self::$api->get('folders/' . kolab_api_tests::folder_uid('INBOX') . '/messages', array('properties' => 'id')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(array('id' => kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1')), $body[0]); + $this->assertSame(array('id' => kolab_api_tests::mapi_uid('INBOX', true, '1')), $body[0]); } /** * Test mail existence check */ function test_mail_exists() { - self::$api->head('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1')); + self::$api->head('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '1')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing note - self::$api->get('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '12345')); + self::$api->get('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test mail info */ function test_mail_info() { - self::$api->get('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1')); + self::$api->get('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '1')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1'), $body['id']); - $this->assertSame(md5('INBOX'), $body['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('INBOX', true, '1'), $body['id']); + $this->assertSame(kolab_api_tests::folder_uid('INBOX'), $body['parent_id']); $this->assertSame('"test" wurde aktualisiert', $body['PidTagSubject']); $this->assertSame(624, $body['PidTagMessageSize']); $this->assertSame('IPM.Note', $body['PidTagMessageClass']); } /** * Test mail create */ function test_mail_create() { return; // @TODO $post = json_encode(array( 'summary' => 'Test summary', 'description' => 'Test description' )); - self::$api->post('mails/' . md5('INBOX'), array(), $post); + self::$api->post('mails/' . kolab_api_tests::folder_uid('INBOX'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['uid'])); // folder does not exists $post = json_encode(array( 'summary' => 'Test summary 2', )); self::$api->post('mails/' . md5('non-existing'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( 'test' => 'Test summary 2', )); - self::$api->post('mails/' . md5('INBOX'), array(), $post); + self::$api->post('mails/' . kolab_api_tests::folder_uid('INBOX'), array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test mail update */ function test_mail_update() { -return; // @TODO + $this->markTestIncomplete('TODO'); + return; // @TODO + $post = json_encode(array( 'summary' => 'Modified summary', 'description' => 'Modified description' )); - self::$api->put('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1'), array(), $post); + self::$api->put('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '1'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1')); + self::$api->get('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '1')); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('Modified summary', $body['summary']); $this->assertSame('Modified description', $body['description']); } /** * Test mail submit */ function test_mail_submit() { - // @TODO + $this->markTestIncomplete('TODO'); } /** * Test mail delete */ function test_mail_delete() { // delete existing note - self::$api->delete('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1')); + self::$api->delete('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '1')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing note - self::$api->get('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '12345')); + self::$api->get('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test mail attachments count */ function test_count_attachments() { - self::$api->head('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '2') . '/attachments'); + self::$api->head('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '2') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(0, (int) $count); - self::$api->head('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '6') . '/attachments'); + self::$api->head('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '6') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(2, (int) $count); } /** * Test listing mail attachments */ function test_list_attachments() { - self::$api->get('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '2') . '/attachments'); + self::$api->get('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '2') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(array(), $body); - self::$api->get('mails/' . kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '6') . '/attachments'); + self::$api->get('mails/' . kolab_api_tests::mapi_uid('INBOX', true, '6') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(2, $body); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '6', '2'), $body[0]['id']); + $this->assertSame(kolab_api_tests::mapi_uid('INBOX', true, '6', '2'), $body[0]['id']); $this->assertSame('attachments', $body[0]['collection']); $this->assertSame('text/plain', $body[0]['PidTagAttachMimeTag']); $this->assertSame('test.txt', $body[0]['PidTagDisplayName']); $this->assertSame('txt', $body[0]['PidTagAttachExtension']); $this->assertSame(4, $body[0]['PidTagAttachSize']); } } diff --git a/tests/Mapistore/Notes.php b/tests/Mapistore/Notes.php index 101cc50..539efe8 100644 --- a/tests/Mapistore/Notes.php +++ b/tests/Mapistore/Notes.php @@ -1,206 +1,206 @@ get('folders/' . md5('Notes') . '/messages'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Notes') . '/messages'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(2, count($body)); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1'), $body[0]['id']); - $this->assertSame(md5('Notes'), $body[0]['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1'), $body[0]['id']); + $this->assertSame(kolab_api_tests::folder_uid('Notes'), $body[0]['parent_id']); $this->assertSame('test', $body[0]['PidTagSubject']); $this->assertSame('notes', $body[0]['collection']); $this->assertSame('IPM.StickyNote', $body[0]['PidTagMessageClass']); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Notes'), '2-2-2-2'), $body[1]['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Notes', true, '2-2-2-2'), $body[1]['id']); $this->assertSame('wwww', $body[1]['PidTagSubject']); $this->assertSame('notes', $body[1]['collection']); $this->assertSame('IPM.StickyNote', $body[1]['PidTagMessageClass']); } /** * Test note existence */ function test_note_exists() { - self::$api->head('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1')); + self::$api->head('notes/' . kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing note - self::$api->get('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '12345')); + self::$api->get('notes/' . kolab_api_tests::mapi_uid('Notes', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test note info */ function test_note_info() { - self::$api->get('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1')); + self::$api->get('notes/' . kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1'), $body['id']); - $this->assertSame(md5('Notes'), $body['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1'), $body['id']); + $this->assertSame(kolab_api_tests::folder_uid('Notes'), $body['parent_id']); $this->assertSame('test', $body['PidTagSubject']); } /** * Test note create */ function test_note_create() { $post = json_encode(array( - 'parent_id' => md5('Notes'), + 'parent_id' => kolab_api_tests::folder_uid('Notes'), 'PidTagSubject' => 'Test summary', 'PidTagBody' => 'Test description' )); self::$api->post('notes', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $uid = $body['id']; $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($uid)); // folder does not exists $post = json_encode(array( 'parent_id' => md5('non-existing'), 'PidTagSubject' => 'Test summary 2', )); self::$api->post('notes', array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( 'test' => 'Test summary 2', )); self::$api->post('notes', array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test note update */ function test_note_update() { $post = json_encode(array( 'PidTagSubject' => 'Modified summary', 'PidTagBody' => 'Modified description', )); - self::$api->put('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1'), array(), $post); + self::$api->put('notes/' . kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1')); + self::$api->get('notes/' . kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1')); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('Modified summary', $body['PidTagSubject']); $this->assertSame('Modified description', $body['PidTagBody']); } /** * Test note delete */ function test_note_delete() { // delete existing note - self::$api->delete('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1')); + self::$api->delete('notes/' . kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing note - self::$api->get('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '12345')); + self::$api->get('notes/' . kolab_api_tests::mapi_uid('Notes', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test mail attachments count */ function test_count_attachments() { // notes do not have attachments in MAPI - self::$api->head('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1') . '/attachments'); + self::$api->head('notes/' . kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1') . '/attachments'); $code = self::$api->response_code(); $this->assertEquals(404, $code); } /** * Test listing mail attachments */ function test_list_attachments() { // notes do not have attachments in MAPI - self::$api->get('notes/' . kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1') . '/attachments'); + self::$api->get('notes/' . kolab_api_tests::mapi_uid('Notes', true, '1-1-1-1') . '/attachments'); $code = self::$api->response_code(); $this->assertEquals(404, $code); } } diff --git a/tests/Mapistore/Tasks.php b/tests/Mapistore/Tasks.php index 765333d..783f0ed 100644 --- a/tests/Mapistore/Tasks.php +++ b/tests/Mapistore/Tasks.php @@ -1,238 +1,238 @@ get('folders/' . md5('Tasks') . '/objects'); + self::$api->get('folders/' . kolab_api_tests::folder_uid('Tasks') . '/objects'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertSame(2, count($body)); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10'), $body[0]['id']); - $this->assertSame(md5('Tasks'), $body[0]['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10'), $body[0]['id']); + $this->assertSame(kolab_api_tests::folder_uid('Tasks'), $body[0]['parent_id']); $this->assertSame('IPM.Task', $body[0]['PidTagMessageClass']); $this->assertSame('tasks', $body[0]['collection']); $this->assertSame('task title', $body[0]['PidTagSubject']); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '20-20-20-20'), $body[1]['id']); - $this->assertSame(md5('Tasks'), $body[1]['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Tasks', true, '20-20-20-20'), $body[1]['id']); + $this->assertSame(kolab_api_tests::folder_uid('Tasks'), $body[1]['parent_id']); $this->assertSame('IPM.Task', $body[1]['PidTagMessageClass']); $this->assertSame('tasks', $body[1]['collection']); $this->assertSame('task', $body[1]['PidTagSubject']); } /** * Test task existence */ function test_task_exists() { - self::$api->head('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10')); + self::$api->head('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(200, $code); $this->assertSame('', $body); // and non-existing task - self::$api->head('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '12345')); + self::$api->head('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } /** * Test task info */ function test_task_info() { - self::$api->get('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10')); + self::$api->get('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10')); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10'), $body['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10'), $body['id']); $this->assertSame('task title', $body['PidTagSubject']); $this->assertSame("task description\nsecond line", $body['PidTagBody']); } /** * Test task create */ function test_task_create() { $post = json_encode(array( - 'parent_id' => md5('Tasks'), + 'parent_id' => kolab_api_tests::folder_uid('Tasks'), 'PidTagSubject' => 'Test summary', 'PidTagBody' => 'Test description', )); self::$api->post('tasks', array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); $this->assertTrue(!empty($body['id'])); // folder does not exists $post = json_encode(array( 'parent_id' => md5('non-existing'), 'PidTagSubject' => 'Test summary 2', )); self::$api->post('tasks', array(), $post); $code = self::$api->response_code(); $this->assertEquals(404, $code); // invalid object data $post = json_encode(array( - 'parent_id' => md5('Tasks'), + 'parent_id' => kolab_api_tests::folder_uid('Tasks'), 'test' => 'Test summary 2', )); self::$api->post('tasks', array(), $post); $code = self::$api->response_code(); $this->assertEquals(422, $code); } /** * Test task update */ function test_task_update() { $post = json_encode(array( 'PidTagSubject' => 'Modified summary', 'PidTagBody' => 'Modified description' )); - self::$api->put('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10'), array(), $post); + self::$api->put('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10'), array(), $post); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); - self::$api->get('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10')); + self::$api->get('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10')); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertSame('Modified summary', $body['PidTagSubject']); $this->assertSame('Modified description', $body['PidTagBody']); } /** * Test counting task attachments */ function test_count_attachments() { // task with an attachment - self::$api->head('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'),'10-10-10-10') . '/attachments'); + self::$api->head('tasks/' . kolab_api_tests::mapi_uid('Tasks', true,'10-10-10-10') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(1, (int) $count); // task with no attachments - self::$api->head('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '20-20-20-20') . '/attachments'); + self::$api->head('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '20-20-20-20') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $count = self::$api->response_header('X-mapistore-rowcount'); $this->assertEquals(200, $code); $this->assertSame('', $body); $this->assertSame(0, (int) $count); } /** * Test listing task attachments */ function test_list_attachments() { - self::$api->get('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10') . '/attachments'); + self::$api->get('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(1, $body); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10', 3), $body[0]['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Tasks', true, '10-10-10-10', 3), $body[0]['id']); $this->assertSame('text/plain', $body[0]['PidTagAttachMimeTag']); $this->assertSame('test.txt', $body[0]['PidTagDisplayName']); $this->assertSame(4, $body[0]['PidTagAttachSize']); // task with no attachments - self::$api->get('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '20-20-20-20') . '/attachments'); + self::$api->get('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '20-20-20-20') . '/attachments'); $code = self::$api->response_code(); $body = self::$api->response_body(); $body = json_decode($body, true); $this->assertEquals(200, $code); $this->assertCount(0, $body); } /** * Test task delete */ function test_task_delete() { // delete existing task - self::$api->delete('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '20-20-20-20')); + self::$api->delete('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '20-20-20-20')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(204, $code); $this->assertSame('', $body); // and non-existing task - self::$api->delete('tasks/' . kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '12345')); + self::$api->delete('tasks/' . kolab_api_tests::mapi_uid('Tasks', true, '12345')); $code = self::$api->response_code(); $body = self::$api->response_body(); $this->assertEquals(404, $code); $this->assertSame('', $body); } } diff --git a/tests/Unit/Filter/Mapistore/Contact.php b/tests/Unit/Filter/Mapistore/Contact.php index cd4a3f4..09d509c 100644 --- a/tests/Unit/Filter/Mapistore/Contact.php +++ b/tests/Unit/Filter/Mapistore/Contact.php @@ -1,405 +1,407 @@ output($data, $context); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d'), $result['id']); - $this->assertSame(md5('Contacts'), $result['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Contacts', false, 'a-b-c-d'), $result['id']); + $this->assertSame(kolab_api_tests::folder_uid('Contacts', false), $result['parent_id']); // $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('20150421T145607Z'), $result['PidTagLastModificationTime']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('20150330', false), $result['PidTagBirthday']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('20150301', false), $result['PidTagWeddingAnniversary']); $this->assertSame('displname', $result['PidTagDisplayName']); $this->assertSame('last', $result['PidTagSurname']); $this->assertSame('test', $result['PidTagGivenName']); $this->assertSame('middlename', $result['PidTagMiddleName']); $this->assertSame('prefx', $result['PidTagDisplayNamePrefix']); $this->assertSame('suff', $result['PidTagGeneration']); $this->assertSame('dsfsdfsdfsdf sdfsdfsdf sdfsdfsfd', $result['PidTagBody']); $this->assertSame('free-busy url', $result['PidLidFreeBusyLocation']); $this->assertSame('title', $result['PidTagTitle']); $this->assertSame('Org', $result['PidTagCompanyName']); $this->assertSame('dept', $result['PidTagDepartmentName']); $this->assertSame('profeion', $result['PidTagProfession']); $this->assertSame('manager name', $result['PidTagManagerName']); $this->assertSame('assist', $result['PidTagAssistant']); $this->assertSame('website', $result['PidTagPersonalHomePage']); $this->assertSame('office street', $result['PidTagOtherAddressStreet']); $this->assertSame('office city', $result['PidTagOtherAddressCity']); $this->assertSame('office state', $result['PidTagOtherAddressStateOrProvince']); $this->assertSame('office zip', $result['PidTagOtherAddressPostalCode']); $this->assertSame('office country', $result['PidTagOtherAddressCountry']); // $this->assertSame('office pobox', $result['PidTagOtherAddressPostOfficeBox']); $this->assertSame('home street', $result['PidTagHomeAddressStreet']); $this->assertSame('home city', $result['PidTagHomeAddressCity']); $this->assertSame('home state', $result['PidTagHomeAddressStateOrProvince']); $this->assertSame('home zip', $result['PidTagHomeAddressPostalCode']); $this->assertSame('home country', $result['PidTagHomeAddressCountry']); // $this->assertSame('home pobox', $result['PidTagHomeAddressPostOfficeBox']); $this->assertSame('work street', $result['PidLidWorkAddressStreet']); $this->assertSame('work city', $result['PidLidWorkAddressCity']); $this->assertSame('work state', $result['PidLidWorkAddressState']); $this->assertSame('work zip', $result['PidLidWorkAddressPostalCode']); $this->assertSame('work country', $result['PidLidWorkAddressCountry']); // $this->assertSame('work pobox', $result['PidLidWorkAddressPostOfficeBox']); $this->assertSame('nick', $result['PidTagNickname']); $this->assertSame(2, $result['PidTagGender']); $this->assertSame('spouse', $result['PidTagSpouseName']); $this->assertSame(array('children', 'children2'), $result['PidTagChildrensNames']); $this->assertSame('home phone', $result['PidTagHomeTelephoneNumber']); $this->assertSame('work phone', $result['PidTagBusinessTelephoneNumber']); $this->assertSame('home fax', $result['PidTagHomeFaxNumber']); $this->assertSame('work fax', $result['PidTagBusinessFaxNumber']); $this->assertSame('mobile', $result['PidTagMobileTelephoneNumber']); $this->assertSame('pager', $result['PidTagPagerTelephoneNumber']); $this->assertSame('car phone', $result['PidTagCarTelephoneNumber']); $this->assertSame('other phone', $result['PidTagOtherTelephoneNumber']); $this->assertSame('im gg', $result['PidLidInstantMessagingAddress']); $this->assertSame('test@mail.ru', $result['PidLidEmail1EmailAddress']); $this->assertSame('work@email.pl', $result['PidLidEmail2EmailAddress']); $this->assertSame('other@email.pl', $result['PidLidEmail3EmailAddress']); $this->assertRegExp('/^cy9.*/', $result['PidTagUserX509Certificate']); // $this->assertRegExp('|^data:application/pgp-keys;base64,|', $result['key'][0]); // $this->assertRegExp('|^data:image/jpeg;base64,|', $result['photo']); // $this->assertSame('individual', $result['kind']); } /** * Test input method */ function test_input() { $api = new kolab_api_filter_mapistore_contact; $data = array( - 'id' => kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d'), - 'parent_id' => md5('Contacts'), + 'id' => kolab_api_tests::mapi_uid('Contacts', false, 'a-b-c-d'), + 'parent_id' => kolab_api_tests::folder_uid('Contacts', false), // 'PidTagLastModificationTime' => kolab_api_filter_mapistore::date_php2mapi('20150421T145607Z'), 'PidTagBirthday' => kolab_api_filter_mapistore::date_php2mapi('20150330', true), 'PidTagWeddingAnniversary' => kolab_api_filter_mapistore::date_php2mapi('20150301', true), 'PidTagDisplayName' => 'displname', 'PidTagSurname' => 'last', 'PidTagGivenName' => 'test', 'PidTagMiddleName' => 'middlename', 'PidTagDisplayNamePrefix' => 'prefx', 'PidTagGeneration' => 'suff', 'PidTagBody' => 'dsfsdfsdfsdf sdfsdfsdf sdfsdfsfd', 'PidLidFreeBusyLocation' => 'free-busy url', 'PidTagTitle' => 'title', 'PidTagCompanyName' => 'Org', 'PidTagDepartmentName' => 'dept', 'PidTagProfession' => 'profeion', 'PidTagManagerName' => 'manager name', 'PidTagAssistant' => 'assist', 'PidTagPersonalHomePage' => 'website', 'PidTagOtherAddressStreet' => 'office street', 'PidTagOtherAddressCity' => 'office city', 'PidTagOtherAddressStateOrProvince' => 'office state', 'PidTagOtherAddressPostalCode' => 'office zip', 'PidTagOtherAddressCountry' => 'office country', // 'PidTagOtherAddressPostOfficeBox' => 'office pobox', 'PidTagHomeAddressStreet' => 'home street', 'PidTagHomeAddressCity' => 'home city', 'PidTagHomeAddressStateOrProvince' => 'home state', 'PidTagHomeAddressPostalCode' => 'home zip', 'PidTagHomeAddressCountry' => 'home country', // 'PidTagHomeAddressPostOfficeBox' => 'home pobox', 'PidLidWorkAddressStreet' => 'work street', 'PidLidWorkAddressCity' => 'work city', 'PidLidWorkAddressState' => 'work state', 'PidLidWorkAddressPostalCode' => 'work zip', 'PidLidWorkAddressCountry' => 'work country', // 'PidLidWorkAddressPostOfficeBox' => 'work pobox', 'PidTagNickname' => 'nick', 'PidTagGender' => 2, 'PidTagSpouseName' => 'spouse', 'PidTagChildrensNames' => array('children', 'children2'), 'PidTagHomeTelephoneNumber' => 'home phone', 'PidTagBusinessTelephoneNumber' => 'work phone', 'PidTagHomeFaxNumber' => 'home fax', 'PidTagBusinessFaxNumber' => 'work fax', 'PidTagMobileTelephoneNumber' => 'mobile', 'PidTagPagerTelephoneNumber' => 'pager', 'PidTagCarTelephoneNumber' => 'car phone', 'PidTagOtherTelephoneNumber' => 'other phone', 'PidLidInstantMessagingAddress' => 'im gg', 'PidLidEmail1EmailAddress' => 'test@mail.ru', 'PidLidEmail2EmailAddress' => 'work@email.pl', 'PidLidEmail3EmailAddress' => 'other@email.pl', 'PidTagUserX509Certificate' => '1234567890', 'PidTagInitials' => 'initials', ); $result = $api->input($data); // $this->assertSame('a-b-c-d', $result['uid']); // $this->assertSame('20150420T141533Z', $result['rev']); // $this->assertSame('individual', $result['kind']); $this->assertSame('displname', $result['fn']); $this->assertSame('last', $result['n']['surname']); $this->assertSame('test', $result['n']['given']); $this->assertSame('middlename', $result['n']['additional']); $this->assertSame('prefx', $result['n']['prefix']); $this->assertSame('suff', $result['n']['suffix']); $this->assertSame('dsfsdfsdfsdf sdfsdfsdf sdfsdfsfd', $result['note']); $this->assertSame('free-busy url', $result['fburl']); $this->assertSame('title', $result['title']); $this->assertSame('Org', $result['group']['org'][0]); $this->assertSame('dept', $result['group']['org'][1]); $this->assertSame('profeion', $result['group']['role']); $this->assertSame('x-manager', $result['group']['related'][0]['parameters']['type']); $this->assertSame('manager name', $result['group']['related'][0]['text']); $this->assertSame('x-assistant', $result['group']['related'][1]['parameters']['type']); $this->assertSame('assist', $result['group']['related'][1]['text']); // $this->assertSame('', $result['group']['adr']['pobox']); $this->assertSame('office street', $result['group']['adr']['street']); $this->assertSame('office city', $result['group']['adr']['locality']); $this->assertSame('office state', $result['group']['adr']['region']); $this->assertSame('office zip', $result['group']['adr']['code']); $this->assertSame('office country', $result['group']['adr']['country']); $this->assertSame(array('website'), $result['url']); $this->assertSame('home', $result['adr'][0]['parameters']['type']); $this->assertSame('home street', $result['adr'][0]['street']); $this->assertSame('home city', $result['adr'][0]['locality']); $this->assertSame('home state', $result['adr'][0]['region']); $this->assertSame('home zip', $result['adr'][0]['code']); $this->assertSame('home country', $result['adr'][0]['country']); $this->assertSame('work', $result['adr'][1]['parameters']['type']); $this->assertSame('work street', $result['adr'][1]['street']); $this->assertSame('work city', $result['adr'][1]['locality']); $this->assertSame('work state', $result['adr'][1]['region']); $this->assertSame('work zip', $result['adr'][1]['code']); $this->assertSame('work country', $result['adr'][1]['country']); $this->assertSame('nick', $result['nickname']); $this->assertSame('spouse', $result['related'][0]['parameters']['type']); $this->assertSame('spouse', $result['related'][0]['text']); $this->assertSame('child', $result['related'][1]['parameters']['type']); $this->assertSame('children', $result['related'][1]['text']); $this->assertSame('child', $result['related'][2]['parameters']['type']); $this->assertSame('children2', $result['related'][2]['text']); $this->assertSame('2015-03-30', $result['bday']); // ? $this->assertSame('2015-03-01', $result['anniversary']); // ? $this->assertSame('M', $result['gender']); $this->assertSame(array('im gg'), $result['impp']); $this->assertSame('home', $result['email'][0]['parameters']['type']); $this->assertSame('test@mail.ru', $result['email'][0]['text']); $this->assertSame('work', $result['email'][1]['parameters']['type']); $this->assertSame('work@email.pl', $result['email'][1]['text']); $this->assertSame('other', $result['email'][2]['parameters']['type']); $this->assertSame('other@email.pl', $result['email'][2]['text']); $this->assertRegExp('|^data:application/pkcs7-mime;base64,|', $result['key'][0]); // $this->assertRegExp('|^data:application/pgp-keys;base64,|', $result['key'][1]); // $this->assertRegExp('|^data:image/jpeg;base64,|', $result['photo']); $this->assertSame('MAPI:PidTagInitials', $result['x-custom'][0]['identifier']); $this->assertSame('initials', $result['x-custom'][0]['value']); $phones = array( 'home' => 'home phone', 'work' => 'work phone', 'faxhome' => 'home fax', 'faxwork' => 'work fax', 'cell' => 'mobile', 'pager' => 'pager', 'x-car' => 'car phone', 'textphone' => 'other phone', ); foreach ($result['tel'] as $tel) { $type = implode('', (array)$tel['parameters']['type']); $text = $tel['text']; if (!empty($phones[$type]) && $phones[$type] == $text) { unset($phones[$type]); } } $this->assertCount(8, $result['tel']); $this->assertCount(0, $phones); self::$original = $result; } /** * Test input method with merge */ function test_input2() { $api = new kolab_api_filter_mapistore_contact; $data = array( - 'id' => kolab_api_filter_mapistore::uid_encode(md5('Contacts'), 'a-b-c-d'), - 'parent_id' => md5('Contacts'), + 'id' => kolab_api_tests::mapi_uid('Contacts', false, 'a-b-c-d'), + 'parent_id' => kolab_api_tests::folder_uid('Contacts', false), // 'PidTagLastModificationTime' => kolab_api_filter_mapistore::date_php2mapi('20150421T145607Z'), 'PidTagBirthday' => kolab_api_filter_mapistore::date_php2mapi('20150430', true), 'PidTagWeddingAnniversary' => kolab_api_filter_mapistore::date_php2mapi('20150401', true), 'PidTagDisplayName' => 'displname1', 'PidTagSurname' => 'last1', 'PidTagGivenName' => 'test1', 'PidTagMiddleName' => 'middlename1', 'PidTagDisplayNamePrefix' => 'prefx1', 'PidTagGeneration' => 'suff1', 'PidTagBody' => 'body1', 'PidLidFreeBusyLocation' => 'free-busy url1', 'PidTagTitle' => 'title1', 'PidTagCompanyName' => 'Org1', 'PidTagDepartmentName' => 'dept1', 'PidTagProfession' => 'profeion1', 'PidTagManagerName' => 'manager name1', 'PidTagAssistant' => 'assist1', 'PidTagPersonalHomePage' => 'website1', 'PidTagOtherAddressStreet' => 'office street1', 'PidTagOtherAddressCity' => 'office city1', 'PidTagOtherAddressStateOrProvince' => 'office state1', 'PidTagOtherAddressPostalCode' => 'office zip1', 'PidTagOtherAddressCountry' => 'office country1', 'PidTagHomeAddressStreet' => 'home street1', 'PidTagHomeAddressCity' => 'home city1', 'PidTagHomeAddressStateOrProvince' => 'home state1', 'PidTagHomeAddressPostalCode' => 'home zip1', 'PidTagHomeAddressCountry' => 'home country1', 'PidLidWorkAddressStreet' => 'work street1', 'PidLidWorkAddressCity' => 'work city1', 'PidLidWorkAddressState' => 'work state1', 'PidLidWorkAddressPostalCode' => 'work zip1', 'PidLidWorkAddressCountry' => 'work country1', 'PidTagNickname' => 'nick1', 'PidTagGender' => 1, 'PidTagSpouseName' => 'spouse1', 'PidTagChildrensNames' => array('children10', 'children20'), 'PidTagHomeTelephoneNumber' => 'home phone1', 'PidTagBusinessTelephoneNumber' => null, 'PidTagHomeFaxNumber' => 'home fax1', 'PidTagBusinessFaxNumber' => 'work fax1', 'PidTagMobileTelephoneNumber' => 'mobile1', 'PidTagPagerTelephoneNumber' => 'pager1', 'PidTagOtherTelephoneNumber' => 'other phone1', 'PidLidInstantMessagingAddress' => 'im gg1', 'PidLidEmail1EmailAddress' => 'test@mail.ru', 'PidLidEmail2EmailAddress' => 'work@email.pl', 'PidTagUserX509Certificate' => '12345678901', - 'PidTagInitials' => 'initials1', + 'PidTagInitials' => 'initials1', + 'PidNameKeywords' => array('work1'), ); $result = $api->input($data, self::$original); // $this->assertSame('a-b-c-d', $result['uid']); // $this->assertSame('20150420T141533Z', $result['rev']); // $this->assertSame('individual', $result['kind']); $this->assertSame('displname1', $result['fn']); $this->assertSame('last1', $result['n']['surname']); $this->assertSame('test1', $result['n']['given']); $this->assertSame('middlename1', $result['n']['additional']); $this->assertSame('prefx1', $result['n']['prefix']); $this->assertSame('suff1', $result['n']['suffix']); $this->assertSame('body1', $result['note']); $this->assertSame('free-busy url1', $result['fburl']); $this->assertSame('title1', $result['title']); $this->assertSame('Org1', $result['group']['org'][0]); $this->assertSame('dept1', $result['group']['org'][1]); $this->assertSame('profeion1', $result['group']['role']); $this->assertSame('x-manager', $result['group']['related'][0]['parameters']['type']); $this->assertSame('manager name1', $result['group']['related'][0]['text']); $this->assertSame('x-assistant', $result['group']['related'][1]['parameters']['type']); $this->assertSame('assist1', $result['group']['related'][1]['text']); $this->assertSame('office street1', $result['group']['adr']['street']); $this->assertSame('office city1', $result['group']['adr']['locality']); $this->assertSame('office state1', $result['group']['adr']['region']); $this->assertSame('office zip1', $result['group']['adr']['code']); $this->assertSame('office country1', $result['group']['adr']['country']); $this->assertSame(array('website1'), $result['url']); $this->assertSame('home', $result['adr'][0]['parameters']['type']); $this->assertSame('home street1', $result['adr'][0]['street']); $this->assertSame('home city1', $result['adr'][0]['locality']); $this->assertSame('home state1', $result['adr'][0]['region']); $this->assertSame('home zip1', $result['adr'][0]['code']); $this->assertSame('home country1', $result['adr'][0]['country']); $this->assertSame('work', $result['adr'][1]['parameters']['type']); $this->assertSame('work street1', $result['adr'][1]['street']); $this->assertSame('work city1', $result['adr'][1]['locality']); $this->assertSame('work state1', $result['adr'][1]['region']); $this->assertSame('work zip1', $result['adr'][1]['code']); $this->assertSame('work country1', $result['adr'][1]['country']); $this->assertSame('nick1', $result['nickname']); $this->assertSame('spouse', $result['related'][0]['parameters']['type']); $this->assertSame('spouse1', $result['related'][0]['text']); $this->assertSame('child', $result['related'][1]['parameters']['type']); $this->assertSame('children10', $result['related'][1]['text']); $this->assertSame('child', $result['related'][2]['parameters']['type']); $this->assertSame('children20', $result['related'][2]['text']); $this->assertSame('2015-04-30', $result['bday']); // ? $this->assertSame('2015-04-01', $result['anniversary']); // ? $this->assertSame('F', $result['gender']); $this->assertSame(array('im gg1'), $result['impp']); $this->assertSame('home', $result['email'][0]['parameters']['type']); $this->assertSame('test@mail.ru', $result['email'][0]['text']); $this->assertSame('work', $result['email'][1]['parameters']['type']); $this->assertSame('work@email.pl', $result['email'][1]['text']); $this->assertSame(null, $result['email'][2]); $this->assertRegExp('|^data:application/pkcs7-mime;base64,|', $result['key'][0]); // $this->assertRegExp('|^data:application/pgp-keys;base64,|', $result['key'][1]); // $this->assertRegExp('|^data:image/jpeg;base64,|', $result['photo']); $this->assertSame('MAPI:PidTagInitials', $result['x-custom'][0]['identifier']); $this->assertSame('initials1', $result['x-custom'][0]['value']); + $this->assertSame(array('work1'), $result['categories']); $phones = array( 'home' => 'home phone1', 'faxhome' => 'home fax1', 'faxwork' => 'work fax1', 'cell' => 'mobile1', 'pager' => 'pager1', 'x-car' => 'car phone', 'textphone' => 'other phone1', ); foreach ($result['tel'] as $tel) { $type = implode('', (array)$tel['parameters']['type']); $text = $tel['text']; if (!empty($phones[$type]) && $phones[$type] == $text) { unset($phones[$type]); } } $this->assertCount(7, $result['tel']); $this->assertCount(0, $phones); // @TODO: updating some deep items (e.g. adr); } /** * Test map method */ function test_map() { $api = new kolab_api_filter_mapistore_contact; $map = $api->map(); $this->assertInternalType('array', $map); $this->assertTrue(!empty($map)); } } diff --git a/tests/Unit/Filter/Mapistore/Event.php b/tests/Unit/Filter/Mapistore/Event.php index ebe6684..fa19ac4 100644 --- a/tests/Unit/Filter/Mapistore/Event.php +++ b/tests/Unit/Filter/Mapistore/Event.php @@ -1,288 +1,288 @@ output($data, $context); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '100-100-100-100'), $result['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Calendar', false, '100-100-100-100'), $result['id']); $this->assertSame('calendars', $result['collection']); $this->assertSame('IPM.Appointment', $result['PidTagMessageClass']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-05-14T13:03:33Z'), $result['PidTagCreationTime']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-05-14T13:50:18Z'), $result['PidTagLastModificationTime']); $this->assertSame(2, $result['PidLidAppointmentSequence']); $this->assertSame(3, $result['PidTagSensitivity']); $this->assertSame('Work', $result['PidNameKeywords'][0]); /* $this->assertSame('/kolab.org/Europe/Berlin', $result['dtstart']['parameters']['tzid']); $this->assertSame('2015-05-15T10:00:00', $result['dtstart']['date-time']); $this->assertSame('/kolab.org/Europe/Berlin', $result['dtend']['parameters']['tzid']); $this->assertSame('2015-05-15T10:30:00', $result['dtend']['date-time']); $this->assertSame('https://some.url', $result['url']); */ $this->assertSame('Summary', $result['PidTagSubject']); $this->assertSame('Description', $result['PidTagBody']); $this->assertSame(2, $result['PidTagImportance']); $this->assertSame('Location', $result['PidLidLocation']); $this->assertSame('German, Mark', $result['recipients'][0]['PidTagDisplayName']); $this->assertSame('mark.german@example.org', $result['recipients'][0]['PidTagEmailAddress']); $this->assertSame(1, $result['recipients'][0]['PidTagRecipientType']); $this->assertSame('Manager, Jane', $result['recipients'][1]['PidTagDisplayName']); $this->assertSame(2, $result['recipients'][1]['PidTagRecipientType']); $this->assertSame('jane.manager@example.org', $result['recipients'][1]['PidTagEmailAddress']); $this->assertSame(15, $result['PidLidReminderDelta']); $this->assertSame(true, $result['PidLidReminderSet']); - $data = kolab_api_tests::get_data('101-101-101-101', md5('Calendar'), 'event', 'json', $context); + $data = kolab_api_tests::get_data('101-101-101-101', 'Calendar', 'event', 'json', $context); $result = $api->output($data, $context); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Calendar'), '101-101-101-101'), $result['id']); + $this->assertSame(kolab_api_tests::mapi_uid('Calendar', false, '101-101-101-101'), $result['id']); $this->assertSame('calendars', $result['collection']); $this->assertSame('IPM.Appointment', $result['PidTagMessageClass']); $this->assertSame(0, $result['PidTagSensitivity']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-05-15T00:00:00Z'), $result['PidLidAppointmentStartWhole']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-05-15T00:00:00Z'), $result['PidLidAppointmentEndWhole']); $this->assertSame(1, $result['PidLidAppointmentSubType']); // recurrence $arp = new kolab_api_filter_mapistore_structure_appointmentrecurrencepattern; $arp->input($result['PidLidAppointmentRecur'], true); $this->assertSame(1, $arp->RecurrencePattern->Period); $this->assertSame(0x200B, $arp->RecurrencePattern->RecurFrequency); $this->assertSame(1, $arp->RecurrencePattern->PatternType); } /** * Test input method */ function test_input() { $api = new kolab_api_filter_mapistore_event; $data = array( 'PidTagCreationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-05-14T13:03:33Z'), 'PidTagLastModificationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-05-14T13:50:18Z'), 'PidLidAppointmentSequence' => 10, 'PidTagSensitivity' => 3, 'PidNameKeywords' => array('work'), 'PidTagSubject' => 'subject', 'PidTagBody' => 'body', 'PidTagImportance' => 2, 'PidLidLocation' => 'location', 'PidLidAppointmentStartWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-05-14T13:03:33Z'), 'PidLidAppointmentEndWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-05-14T16:00:00Z'), 'PidLidReminderDelta' => 15, 'PidLidReminderSet' => true, ); $result = $api->input($data); $this->assertSame('subject', $result['summary']); $this->assertSame('body', $result['description']); $this->assertSame(10, $result['sequence']); $this->assertSame('confidential', $result['class']); $this->assertSame(array('work'), $result['categories']); $this->assertSame('location', $result['location']); $this->assertSame(1, $result['priority']); $this->assertSame('2015-05-14T13:03:33Z', $result['created']); $this->assertSame('2015-05-14T13:50:18Z', $result['dtstamp']); $this->assertSame('2015-05-14T13:03:33Z', $result['dtstart']); $this->assertSame('2015-05-14T16:00:00Z', $result['dtend']); $this->assertSame('DISPLAY', $result['valarm'][0]['properties']['action']); $this->assertSame('Reminder', $result['valarm'][0]['properties']['description']); $this->assertSame('-PT15M', $result['valarm'][0]['properties']['trigger']['duration']); self::$original = $result; $data = array( // all-day event 'PidLidAppointmentStartWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-05-14T00:00:00Z'), 'PidLidAppointmentEndWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-05-14T00:00:00Z'), 'PidLidAppointmentSubType' => 1, 'PidLidReminderSet' => false, // @TODO: recurrence, exceptions, alarms, attendees ); $result = $api->input($data); $this->assertSame('2015-05-14', $result['dtstart']); $this->assertSame('2015-05-14', $result['dtend']); $this->assertSame(array(), $result['valarm']); } /** * Test input method with merge */ function test_input2() { $api = new kolab_api_filter_mapistore_event; $data = array( // 'PidTagCreationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-05-14T13:03:33Z'), // 'PidTagLastModificationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-05-14T13:50:18Z'), 'PidLidAppointmentSequence' => 20, 'PidTagSensitivity' => 2, 'PidNameKeywords' => array('work1'), 'PidTagSubject' => 'subject1', 'PidTagBody' => 'body1', 'PidTagImportance' => 1, 'PidLidLocation' => 'location1', 'PidLidAppointmentStartWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-05-15T13:03:33Z'), 'PidLidAppointmentEndWhole' => kolab_api_filter_mapistore::date_php2mapi('2015-05-15T16:00:00Z'), 'PidLidReminderDelta' => 25, 'PidLidReminderSet' => true, ); $result = $api->input($data, self::$original); $this->assertSame('subject1', $result['summary']); $this->assertSame('body1', $result['description']); $this->assertSame(20, $result['sequence']); $this->assertSame('private', $result['class']); $this->assertSame(array('work1'), $result['categories']); $this->assertSame('location1', $result['location']); $this->assertSame(5, $result['priority']); // $this->assertSame('2015-05-14T13:03:33Z', $result['created']); // $this->assertSame('2015-05-14T13:50:18Z', $result['dtstamp']); $this->assertSame('2015-05-15T13:03:33Z', $result['dtstart']); $this->assertSame('2015-05-15T16:00:00Z', $result['dtend']); $this->assertSame('DISPLAY', $result['valarm'][0]['properties']['action']); $this->assertSame('Reminder', $result['valarm'][0]['properties']['description']); $this->assertSame('-PT25M', $result['valarm'][0]['properties']['trigger']['duration']); // @TODO: recurrence, exceptions, attendees } /** * Test map method */ function test_map() { $api = new kolab_api_filter_mapistore_event; $map = $api->map(); $this->assertInternalType('array', $map); $this->assertTrue(!empty($map)); } /** * Test recurrence_to_kolab */ function test_recurrence_to_kolab() { // empty result $result = kolab_api_filter_mapistore_event::recurrence_to_kolab(''); $this->assertSame(array(), $result); // build complete AppointmentRecurrencePattern structure $structure = new kolab_api_filter_mapistore_structure_appointmentrecurrencepattern; $exceptioninfo = new kolab_api_filter_mapistore_structure_exceptioninfo; $recurrencepattern = new kolab_api_filter_mapistore_structure_recurrencepattern; $extendedexception = new kolab_api_filter_mapistore_structure_extendedexception; $highlight = new kolab_api_filter_mapistore_structure_changehighlight; $highlight->ChangeHighlightValue = 4; $extendedexception->ChangeHighlight = $highlight; $extendedexception->StartDateTime = 0x0CBC9934; $extendedexception->EndDateTime = 0x0CBC9952; $extendedexception->OriginalStartDate = 0x0CBC98F8; $extendedexception->WideCharSubject = 'Simple Recurrence with exceptions'; $extendedexception->WideCharLocation = '34/4141'; $recurrencepattern->RecurFrequency = 0x200b; $recurrencepattern->PatternType = 1; $recurrencepattern->CalendarType = 0; $recurrencepattern->FirstDateTime = 0x000021C0; $recurrencepattern->Period = 1; $recurrencepattern->SlidingFlag = 0; $recurrencepattern->PatternTypeSpecific = 0x00000032; $recurrencepattern->EndType = 0x00002022; $recurrencepattern->OccurrenceCount = 12; $recurrencepattern->FirstDOW = 0; $recurrencepattern->DeletedInstanceDates = array(0x0CBC96A0); $recurrencepattern->ModifiedInstanceDates = array(0x0CBC96A0); $recurrencepattern->StartDate = 213655680; $recurrencepattern->EndDate = 0x0CBCAD20; $exceptioninfo->StartDateTime = 0x0CBC9934; $exceptioninfo->EndDateTime = 0x0CBC9952; $exceptioninfo->OriginalStartDate = 0x0CBC98F8; $exceptioninfo->Subject = 'Simple Recurrence with exceptions'; $exceptioninfo->Location = '34/4141'; $structure->StartTimeOffset = 600; $structure->EndTimeOffset = 630; $structure->ExceptionInfo = array($exceptioninfo); $structure->RecurrencePattern = $recurrencepattern; $structure->ExtendedException = array($extendedexception); $rule = $structure->output(true); $result = kolab_api_filter_mapistore_event::recurrence_to_kolab($rule); $this->assertSame('WEEKLY', $result['freq']); } /** * Test recurrence_from_kolab */ function test_recurrence_from_kolab() { $event = array( 'PidLidAppointmentStartWhole' => 123456789, ); $rule = array( 'freq' => 'MONTHLY', 'bymonthday' => 5, 'count' => 10, 'interval' => 2, ); $result = kolab_api_filter_mapistore_event::recurrence_from_kolab($rule, $event); $arp = new kolab_api_filter_mapistore_structure_appointmentrecurrencepattern; $arp->input($result, true); $this->assertSame(kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTH, $arp->RecurrencePattern->PatternType); $this->assertSame(kolab_api_filter_mapistore_structure_recurrencepattern::RECURFREQUENCY_MONTHLY, $arp->RecurrencePattern->RecurFrequency); $this->assertSame(5, $arp->RecurrencePattern->PatternTypeSpecific); $this->assertSame(10, $arp->RecurrencePattern->OccurrenceCount); $this->assertSame(2, $arp->RecurrencePattern->Period); // test $type=task $task = array( 'PidLidCommonStart' => 123456789, ); $rule = array( 'freq' => 'YEARLY', 'bymonth' => 5, 'bymonthday' => 1, 'count' => 10, ); $result = kolab_api_filter_mapistore_event::recurrence_from_kolab($rule, $task, 'task'); $rp = new kolab_api_filter_mapistore_structure_recurrencepattern; $rp->input($result, true); $this->assertSame(kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_MONTHNTH, $rp->PatternType); $this->assertSame(kolab_api_filter_mapistore_structure_recurrencepattern::RECURFREQUENCY_YEARLY, $rp->RecurFrequency); $this->assertSame(1, $rp->PatternTypeSpecific[1]); $this->assertSame(10, $rp->OccurrenceCount); $this->assertSame(12, $rp->Period); // @TODO: test other $rp properties } } diff --git a/tests/Unit/Filter/Mapistore/Mail.php b/tests/Unit/Filter/Mapistore/Mail.php index 46f438e..8ee395e 100644 --- a/tests/Unit/Filter/Mapistore/Mail.php +++ b/tests/Unit/Filter/Mapistore/Mail.php @@ -1,73 +1,73 @@ output($data, $context); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '1'), $result['id']); - $this->assertSame(md5('INBOX'), $result['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('INBOX', false, '1'), $result['id']); + $this->assertSame(kolab_api_tests::folder_uid('INBOX', false), $result['parent_id']); $this->assertSame('mails', $result['collection']); $this->assertSame('IPM.Note', $result['PidTagMessageClass']); $this->assertSame('"test" wurde aktualisiert', $result['PidTagSubject']); $this->assertSame(624, $result['PidTagMessageSize']); $this->assertCount(1, $result['recipients']); $this->assertSame('mark.german@example.org', $result['recipients'][0]['PidTagSmtpAddress']); $this->assertSame(1, $result['recipients'][0]['PidTagRecipientType']); - $data = kolab_api_tests::get_data('2', md5('INBOX'), 'mail', 'json', $context); + $data = kolab_api_tests::get_data('2', 'INBOX', 'mail', 'json', $context); $result = $api->output($data, $context); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('INBOX'), '2'), $result['id']); - $this->assertSame(md5('INBOX'), $result['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('INBOX', false, '2'), $result['id']); + $this->assertSame(kolab_api_tests::folder_uid('INBOX', false), $result['parent_id']); $this->assertSame('IPM.Note', $result['PidTagMessageClass']); $this->assertSame('Re: dsda', $result['PidTagSubject']); $this->assertSame(807, $result['PidTagMessageSize']); $this->assertCount(1, $result['recipients']); $this->assertSame('mark.german@example.org', $result['recipients'][0]['PidTagSmtpAddress']); $this->assertSame('German, Mark', $result['recipients'][0]['PidTagDisplayName']); $this->assertSame(1, $result['recipients'][0]['PidTagRecipientType']); } /** * Test input method */ function test_input() { // @TODO $this->markTestIncomplete('TODO'); } /** * Test input method with merge */ function test_input2() { // @TODO $this->markTestIncomplete('TODO'); } /** * Test map method */ function test_map() { $api = new kolab_api_filter_mapistore_mail; $map = $api->map(); $this->assertInternalType('array', $map); $this->assertTrue(!empty($map)); } } diff --git a/tests/Unit/Filter/Mapistore/Note.php b/tests/Unit/Filter/Mapistore/Note.php index 34d3db0..0bb69f0 100644 --- a/tests/Unit/Filter/Mapistore/Note.php +++ b/tests/Unit/Filter/Mapistore/Note.php @@ -1,132 +1,132 @@ output($data, $context); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1'), $result['id']); - $this->assertSame(md5('Notes'), $result['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Notes', false, '1-1-1-1'), $result['id']); + $this->assertSame(kolab_api_tests::folder_uid('Notes', false), $result['parent_id']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-01-20T11:44:59Z'), $result['PidTagCreationTime']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-01-22T11:30:17Z'), $result['PidTagLastModificationTime']); // $this->assertSame('PUBLIC', $result['classification']); $this->assertSame('test', $result['PidTagSubject']); $this->assertRegexp('//', $result['PidTagBody']); $this->assertSame(100, $result['PidLidNoteX']); $this->assertSame(200, $result['PidLidNoteY']); } /** * Test input method */ function test_input() { $api = new kolab_api_filter_mapistore_note; $data = array( - 'id' => kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1'), - 'parent_id' => md5('Notes'), + 'id' => kolab_api_tests::mapi_uid('Notes', false, '1-1-1-1'), + 'parent_id' => kolab_api_tests::folder_uid('Notes', false), 'PidTagCreationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-01-20T11:44:59Z'), 'PidTagLastModificationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-01-22T11:30:17Z'), 'PidTagSubject' => 'subject', 'PidTagBody' => 'body', 'PidLidNoteColor' => 1, 'PidLidNoteHeight' => 100, 'PidLidNoteWidth' => 200, 'PidLidNoteX' => 300, 'PidLidNoteY' => 400, + 'PidNameKeywords' => array('work1'), ); $result = $api->input($data); -// $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1'), $result['uid']); -// $this->assertSame(md5('Notes'), $result['parent']); +// $this->assertSame(kolab_api_tests::mapi_uid('Notes', false, '1-1-1-1'), $result['uid']); +// $this->assertSame(kolab_api_tests::folder_uid('Notes', false), $result['parent']); $this->assertSame('2015-01-20T11:44:59Z', $result['creation-date']); $this->assertSame('2015-01-22T11:30:17Z', $result['last-modification-date']); $this->assertSame('subject', $result['summary']); $this->assertSame('body', $result['description']); $this->assertSame('MAPI:PidLidNoteColor', $result['x-custom'][0]['identifier']); $this->assertSame(1, $result['x-custom'][0]['value']); $this->assertSame('MAPI:PidLidNoteHeight', $result['x-custom'][1]['identifier']); $this->assertSame(100, $result['x-custom'][1]['value']); $this->assertSame('MAPI:PidLidNoteWidth', $result['x-custom'][2]['identifier']); $this->assertSame(200, $result['x-custom'][2]['value']); $this->assertSame('MAPI:PidLidNoteX', $result['x-custom'][3]['identifier']); $this->assertSame(300, $result['x-custom'][3]['value']); $this->assertSame('MAPI:PidLidNoteY', $result['x-custom'][4]['identifier']); $this->assertSame(400, $result['x-custom'][4]['value']); + $this->assertSame(array('work1'), $result['categories']); self::$original = $result; } /** * Test input method with merge */ function test_input2() { $api = new kolab_api_filter_mapistore_note; $data = array( - 'id' => kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1'), - 'parent_id' => md5('Notes'), + 'id' => kolab_api_tests::mapi_uid('Notes', false, '1-1-1-1'), + 'parent_id' => kolab_api_tests::folder_uid('Notes', false), // 'PidTagCreationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-01-20T11:44:59Z'), // 'PidTagLastModificationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-01-22T11:30:17Z'), 'PidTagSubject' => 'subject1', 'PidTagBody' => 'body1', 'PidLidNoteX' => 250, 'PidLidNoteColor' => null, ); $result = $api->input($data, self::$original); -// $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Notes'), '1-1-1-1'), $result['uid']); -// $this->assertSame(md5('Notes'), $result['parent']); // $this->assertSame('2015-01-20T11:44:59Z', $result['creation-date']); // $this->assertSame('2015-01-22T11:30:17Z', $result['last-modification-date']); $this->assertSame('subject1', $result['summary']); $this->assertSame('body1', $result['description']); $this->assertSame('MAPI:PidLidNoteHeight', $result['x-custom'][0]['identifier']); $this->assertSame(100, $result['x-custom'][0]['value']); $this->assertSame('MAPI:PidLidNoteWidth', $result['x-custom'][1]['identifier']); $this->assertSame(200, $result['x-custom'][1]['value']); $this->assertSame('MAPI:PidLidNoteX', $result['x-custom'][2]['identifier']); $this->assertSame(250, $result['x-custom'][2]['value']); $this->assertSame('MAPI:PidLidNoteY', $result['x-custom'][3]['identifier']); $this->assertSame(400, $result['x-custom'][3]['value']); $this->assertCount(4, $result['x-custom']); // test unsetting values $api = new kolab_api_filter_mapistore_note; $data = array( 'PidTagSubject' => '', ); $result = $api->input($data, self::$original); $this->assertSame('', $result['summary']); } /** * Test map method */ function test_map() { $api = new kolab_api_filter_mapistore_note; $map = $api->map(); $this->assertInternalType('array', $map); $this->assertTrue(!empty($map)); } } diff --git a/tests/Unit/Filter/Mapistore/Task.php b/tests/Unit/Filter/Mapistore/Task.php index 3430ac7..eead53e 100644 --- a/tests/Unit/Filter/Mapistore/Task.php +++ b/tests/Unit/Filter/Mapistore/Task.php @@ -1,162 +1,163 @@ output($data, $context); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10'), $result['id']); - $this->assertSame(md5('Tasks'), $result['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Tasks', false, '10-10-10-10'), $result['id']); + $this->assertSame(kolab_api_tests::folder_uid('Tasks', false), $result['parent_id']); $this->assertSame('IPM.Task', $result['PidTagMessageClass']); $this->assertSame('tasks', $result['collection']); $this->assertSame('task title', $result['PidTagSubject']); $this->assertSame("task description\nsecond line", $result['PidTagBody']); $this->assertSame(0.56, $result['PidLidPercentComplete']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-04-20T14:22:18Z', true), $result['PidTagLastModificationTime']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-04-20T14:22:18Z', true), $result['PidTagCreationTime']); $this->assertSame(8, $result['PidLidTaskActualEffort']); + /* $this->assertSame('German, Mark', $result['organizer']['parameters']['cn']); $this->assertSame('mailto:%3Cmark.german%40example.org%3E', $result['organizer']['cal-address']); */ - $data = kolab_api_tests::get_data('20-20-20-20', md5('Tasks'), 'task', 'json', $context); + $data = kolab_api_tests::get_data('20-20-20-20', 'Tasks', 'task', 'json', $context); $result = $api->output($data, $context); - $this->assertSame(kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '20-20-20-20'), $result['id']); - $this->assertSame(md5('Tasks'), $result['parent_id']); + $this->assertSame(kolab_api_tests::mapi_uid('Tasks', false, '20-20-20-20'), $result['id']); + $this->assertSame(kolab_api_tests::folder_uid('Tasks', false), $result['parent_id']); $this->assertSame('IPM.Task', $result['PidTagMessageClass']); $this->assertSame('tasks', $result['collection']); $this->assertSame('task', $result['PidTagSubject']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-04-20', true), $result['PidLidTaskStartDate']); $this->assertSame(kolab_api_filter_mapistore::date_php2mapi('2015-04-27', true), $result['PidLidTaskDueDate']); /* $this->assertSame('NEEDS-ACTION', $result['status']); $this->assertSame('Manager, Jane', $result['attendee']['parameters']['cn']); $this->assertSame('NEEDS-ACTION', $result['attendee']['parameters']['partstat']); $this->assertSame('REQ-PARTICIPANT', $result['attendee']['parameters']['role']); $this->assertSame(true, $result['attendee']['parameters']['rsvp']); $this->assertSame('mailto:%3Cjane.manager%40example.org%3E', $result['attendee']['cal-address']); */ // recurrence $rp = new kolab_api_filter_mapistore_structure_recurrencepattern; $rp->input($result['PidLidTaskRecurrence'], true); $this->assertSame(true, $result['PidLidTaskFRecurring']); $this->assertSame(kolab_api_filter_mapistore_structure_recurrencepattern::PATTERNTYPE_DAY, $rp->PatternType); $this->assertSame(kolab_api_filter_mapistore_structure_recurrencepattern::RECURFREQUENCY_DAILY, $rp->RecurFrequency); } /** * Test input method */ function test_input() { $api = new kolab_api_filter_mapistore_task; $data = array( - 'id' => kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10'), - 'parent_id' => md5('Tasks'), + 'id' => kolab_api_tests::mapi_uid('Tasks', false, '10-10-10-10'), + 'parent_id' => kolab_api_tests::folder_uid('Tasks', false), 'PidTagCreationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-01-20T11:44:59Z'), 'PidTagLastModificationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-01-22T11:30:17Z'), 'PidTagMessageClass' => 'IPM.Task', 'PidTagSubject' => 'subject', 'PidLidPercentComplete' => 0.56, 'PidTagBody' => 'body', 'PidLidTaskStartDate' => kolab_api_filter_mapistore::date_php2mapi('2015-04-20', true), 'PidLidTaskDueDate' => kolab_api_filter_mapistore::date_php2mapi('2015-04-27', true), 'PidLidTaskActualEffort' => 16, 'PidLidTaskEstimatedEffort' => 20, - ); + 'PidNameKeywords' => array('work1'), + ); $result = $api->input($data); self::$original = $result; $this->assertSame('subject', $result['summary']); $this->assertSame('body', $result['description']); $this->assertSame(56, $result['percent-complete']); $this->assertSame('2015-01-20T11:44:59Z', $result['created']); $this->assertSame('2015-01-22T11:30:17Z', $result['dtstamp']); $this->assertSame('2015-04-20', $result['dtstart']); $this->assertSame('2015-04-27', $result['due']); $this->assertSame('MAPI:PidLidTaskActualEffort', $result['x-custom'][0]['identifier']); $this->assertSame(16, $result['x-custom'][0]['value']); $this->assertSame('MAPI:PidLidTaskEstimatedEffort', $result['x-custom'][1]['identifier']); $this->assertSame(20, $result['x-custom'][1]['value']); + $this->assertSame(array('work1'), $result['categories']); $data = array( 'PidLidTaskComplete' => true, 'PidLidTaskDateCompleted' => kolab_api_filter_mapistore::date_php2mapi('2015-04-20', true), 'PidLidTaskActualEffort' => 100, 'PidLidTaskEstimatedEffort' => 100, // @TODO: recurrence ); $result = $api->input($data); $this->assertSame('COMPLETED', $result['status']); // $this->assertSame(100, $result['x-custom']); } /** * Test input method with merge */ function test_input2() { $api = new kolab_api_filter_mapistore_task; $data = array( -// 'id' => kolab_api_filter_mapistore::uid_encode(md5('Tasks'), '10-10-10-10'), -// 'parent_id' => md5('Tasks'), 'PidTagCreationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-01-20T12:44:59Z'), 'PidTagLastModificationTime' => kolab_api_filter_mapistore::date_php2mapi('2015-01-22T12:30:17Z'), // 'PidTagMessageClass' => 'IPM.Task', 'PidTagSubject' => 'subject1', 'PidLidPercentComplete' => 0.66, 'PidTagBody' => 'body1', 'PidLidTaskStartDate' => kolab_api_filter_mapistore::date_php2mapi('2015-04-21', true), 'PidLidTaskDueDate' => kolab_api_filter_mapistore::date_php2mapi('2015-04-28', true), 'PidLidTaskActualEffort' => 21, 'PidLidTaskEstimatedEffort' => null, ); $result = $api->input($data, self::$original); self::$original = $result; $this->assertSame('subject1', $result['summary']); $this->assertSame('body1', $result['description']); $this->assertSame(66, $result['percent-complete']); $this->assertSame('2015-01-20T12:44:59Z', $result['created']); $this->assertSame('2015-01-22T12:30:17Z', $result['dtstamp']); $this->assertSame('2015-04-21', $result['dtstart']); $this->assertSame('2015-04-28', $result['due']); $this->assertSame('MAPI:PidLidTaskActualEffort', $result['x-custom'][0]['identifier']); $this->assertSame(21, $result['x-custom'][0]['value']); $this->assertCount(1, $result['x-custom']); } /** * Test map method */ function test_map() { $api = new kolab_api_filter_mapistore_task; $map = $api->map(); $this->assertInternalType('array', $map); $this->assertTrue(!empty($map)); } } diff --git a/tests/Unit/Output/Json.php b/tests/Unit/Output/Json.php index 715281f..942a0e4 100644 --- a/tests/Unit/Output/Json.php +++ b/tests/Unit/Output/Json.php @@ -1,37 +1,34 @@ markTestIncomplete('TODO'); } /** * Test xml_to_array method */ function test_xml_to_array() { - // @TODO $this->markTestIncomplete('TODO'); } /** * Test parse_array_result method */ function test_parse_array_result() { - // @TODO $this->markTestIncomplete('TODO'); } } diff --git a/tests/Unit/Output/Json/Contact.php b/tests/Unit/Output/Json/Contact.php index 788cc5c..2fdb2d3 100644 --- a/tests/Unit/Output/Json/Contact.php +++ b/tests/Unit/Output/Json/Contact.php @@ -1,99 +1,99 @@ element($object); $this->assertSame('a-b-c-d', $result['uid']); // $this->assertSame('3.1.0', $result['x-kolab-version']); // $this->assertSame('20150420T141533Z', $result['rev']); $this->assertSame('individual', $result['kind']); $this->assertSame('displname', $result['fn']); $this->assertSame('last', $result['n']['surname']); $this->assertSame('test', $result['n']['given']); $this->assertSame('middlename', $result['n']['additional']); $this->assertSame('prefx', $result['n']['prefix']); $this->assertSame('suff', $result['n']['suffix']); $this->assertSame('dsfsdfsdfsdf sdfsdfsdf sdfsdfsfd', $result['note']); $this->assertSame('free-busy url', $result['fburl']); $this->assertSame(array('title'), $result['title']); $this->assertSame('Org', $result['group']['org'][0]); $this->assertSame('dept', $result['group']['org'][1]); $this->assertSame('profeion', $result['group']['role']); $this->assertSame('x-manager', $result['group']['related'][0]['parameters']['type']); $this->assertSame('manager name', $result['group']['related'][0]['text']); $this->assertSame('x-assistant', $result['group']['related'][1]['parameters']['type']); $this->assertSame('assist', $result['group']['related'][1]['text']); // $this->assertSame('', $result['group']['adr']['parameters']); // $this->assertSame('', $result['group']['adr']['pobox']); // $this->assertSame('', $result['group']['adr']['ext']); $this->assertSame('office street', $result['group']['adr']['street']); $this->assertSame('office city', $result['group']['adr']['locality']); $this->assertSame('office state', $result['group']['adr']['region']); $this->assertSame('office zip', $result['group']['adr']['code']); $this->assertSame('office country', $result['group']['adr']['country']); $this->assertSame('website', $result['url'][0]); $this->assertSame('home', $result['adr'][0]['parameters']['type']); $this->assertSame('home street', $result['adr'][0]['street']); $this->assertSame('home city', $result['adr'][0]['locality']); $this->assertSame('home state', $result['adr'][0]['region']); $this->assertSame('home zip', $result['adr'][0]['code']); $this->assertSame('home country', $result['adr'][0]['country']); $this->assertSame('work', $result['adr'][1]['parameters']['type']); $this->assertSame('work street', $result['adr'][1]['street']); $this->assertSame('work city', $result['adr'][1]['locality']); $this->assertSame('work state', $result['adr'][1]['region']); $this->assertSame('work zip', $result['adr'][1]['code']); $this->assertSame('work country', $result['adr'][1]['country']); $this->assertSame('nick', $result['nickname']); $this->assertSame('spouse', $result['related'][0]['parameters']['type']); $this->assertSame('spouse', $result['related'][0]['text']); $this->assertSame('child', $result['related'][1]['parameters']['type']); $this->assertSame('children', $result['related'][1]['text']); $this->assertSame('child', $result['related'][2]['parameters']['type']); $this->assertSame('children2', $result['related'][2]['text']); $this->assertSame('20150330', $result['bday']); // ? $this->assertSame('20150301', $result['anniversary']); // ? $this->assertRegExp('|^data:image/jpeg;base64,|', $result['photo']); $this->assertSame('M', $result['gender']); $this->assertSame('home', $result['tel'][0]['parameters']['type']); $this->assertSame('home phone', $result['tel'][0]['text']); $this->assertSame('work', $result['tel'][1]['parameters']['type']); $this->assertSame('work phone', $result['tel'][1]['text']); $this->assertSame('fax', $result['tel'][2]['parameters']['type'][0]); $this->assertSame('home', $result['tel'][2]['parameters']['type'][1]); $this->assertSame('home fax', $result['tel'][2]['text']); $this->assertSame('fax', $result['tel'][3]['parameters']['type'][0]); $this->assertSame('work', $result['tel'][3]['parameters']['type'][1]); $this->assertSame('work fax', $result['tel'][3]['text']); $this->assertSame('cell', $result['tel'][4]['parameters']['type']); $this->assertSame('mobile', $result['tel'][4]['text']); $this->assertSame('pager', $result['tel'][5]['parameters']['type']); $this->assertSame('pager', $result['tel'][5]['text']); $this->assertSame('x-car', $result['tel'][6]['parameters']['type']); $this->assertSame('car phone', $result['tel'][6]['text']); $this->assertSame('textphone', $result['tel'][7]['parameters']['type']); $this->assertSame('other phone', $result['tel'][7]['text']); $this->assertSame('im gg', $result['impp'][0]); $this->assertSame('home', $result['email'][0]['parameters']['type']); $this->assertSame('test@mail.ru', $result['email'][0]['text']); $this->assertSame('work', $result['email'][1]['parameters']['type']); $this->assertSame('work@email.pl', $result['email'][1]['text']); $this->assertSame('other@email.pl', $result['email'][2]); $this->assertRegExp('|^data:application/pgp-keys;base64,|', $result['key'][0]); $this->assertRegExp('|^data:application/pkcs7-mime;base64,|', $result['key'][1]); } } diff --git a/tests/Unit/Output/Json/Event.php b/tests/Unit/Output/Json/Event.php index fa65f47..c091cb8 100644 --- a/tests/Unit/Output/Json/Event.php +++ b/tests/Unit/Output/Json/Event.php @@ -1,60 +1,60 @@ element($object); $this->assertSame('100-100-100-100', $result['uid']); $this->assertSame('2015-05-14T13:03:33Z', $result['created']); $this->assertSame('2015-05-14T13:50:18Z', $result['dtstamp']); $this->assertSame(2, $result['sequence']); $this->assertSame('CONFIDENTIAL', $result['class']); $this->assertSame('Work', $result['categories'][0]); $this->assertSame('/kolab.org/Europe/Berlin', $result['dtstart']['parameters']['tzid']); $this->assertSame('2015-05-15T10:00:00', $result['dtstart']['date-time']); $this->assertSame('/kolab.org/Europe/Berlin', $result['dtend']['parameters']['tzid']); $this->assertSame('2015-05-15T10:30:00', $result['dtend']['date-time']); $this->assertSame('Summary', $result['summary']); $this->assertSame('Description', $result['description']); $this->assertSame(1, $result['priority']); $this->assertSame('Location', $result['location']); $this->assertSame('German, Mark', $result['organizer']['parameters']['cn']); $this->assertSame('mailto:%3Cmark.german%40example.org%3E', $result['organizer']['cal-address']); $this->assertSame('https://some.url', $result['url']); $this->assertSame('Manager, Jane', $result['attendee'][0]['parameters']['cn']); $this->assertSame('NEEDS-ACTION', $result['attendee'][0]['parameters']['partstat']); $this->assertSame('REQ-PARTICIPANT', $result['attendee'][0]['parameters']['role']); $this->assertSame(true, $result['attendee'][0]['parameters']['rsvp']); $this->assertSame('mailto:%3Cjane.manager%40example.org%3E', $result['attendee'][0]['cal-address']); $this->assertSame('image/jpeg', $result['attach'][0]['parameters']['fmttype']); $this->assertSame('photo-mini.jpg', $result['attach'][0]['parameters']['x-label']); $this->assertSame('cid:photo-mini.1431611291.28810.jpg', $result['attach'][0]['uri']); $this->assertSame('DISPLAY', $result['valarm'][0]['properties']['action']); $this->assertSame('Summary', $result['valarm'][0]['properties']['description']); $this->assertSame('START', $result['valarm'][0]['properties']['trigger']['parameters']['related']); $this->assertSame('-PT15M', $result['valarm'][0]['properties']['trigger']['duration']); - $object = kolab_api_tests::get_data('101-101-101-101', md5('Calendar'), 'event', null, $context); + $object = kolab_api_tests::get_data('101-101-101-101', 'Calendar', 'event', null, $context); $result = $output->element($object); $this->assertSame('101-101-101-101', $result['uid']); $this->assertSame('PUBLIC', $result['class']); $this->assertSame('2015-05-15', $result['dtstart']); $this->assertSame('2015-05-15', $result['dtend']); $this->assertSame('WEEKLY', $result['rrule']['recur']['freq']); $this->assertSame('MO', $result['rrule']['recur']['byday']); } } diff --git a/tests/Unit/Output/Json/Mail.php b/tests/Unit/Output/Json/Mail.php index a9805e2..a22a316 100644 --- a/tests/Unit/Output/Json/Mail.php +++ b/tests/Unit/Output/Json/Mail.php @@ -1,49 +1,49 @@ element($object); $this->assertSame('1', $result['uid']); $this->assertSame('"test" wurde aktualisiert', $result['subject']); $this->assertSame(624, $result['size']); $this->assertSame(array( 'address' => 'mark.german@example.org', 'name' => 'Mark German' ), $result['from']); $this->assertSame(array(array( 'address' => 'mark.german@example.org' )), $result['to']); $this->assertSame('text/plain', $result['content-type']); - $object = kolab_api_tests::get_data('2', md5('INBOX'), 'mail', null, $context); + $object = kolab_api_tests::get_data('2', 'INBOX', 'mail', null, $context); $result = $output->element($object); $this->assertSame('2', $result['uid']); $this->assertSame('Re: dsda', $result['subject']); $this->assertSame(807, $result['size']); $this->assertSame('text/plain', $result['content-type']); $this->assertSame(array( 'address' => 'mark.german@example.org', 'name' => 'German, Mark' ), $result['from']); $this->assertSame(array(array( 'address' => 'mark.german@example.org', 'name' => 'German, Mark' )), $result['to']); } } diff --git a/tests/Unit/Output/Json/Note.php b/tests/Unit/Output/Json/Note.php index 6301435..9059792 100644 --- a/tests/Unit/Output/Json/Note.php +++ b/tests/Unit/Output/Json/Note.php @@ -1,32 +1,32 @@ element($object); $this->assertSame('1-1-1-1', $result['uid']); $this->assertSame('2015-01-20T11:44:59Z', $result['creation-date']); $this->assertSame('2015-01-22T11:30:17Z', $result['last-modification-date']); $this->assertSame('PUBLIC', $result['classification']); $this->assertSame('test', $result['summary']); $this->assertRegexp('//', $result['description']); $this->assertSame('MAPI:PidLidNoteX', $result['x-custom'][0]['identifier']); $this->assertSame('100', $result['x-custom'][0]['value']); $this->assertSame('MAPI:PidLidNoteY', $result['x-custom'][1]['identifier']); $this->assertSame('200', $result['x-custom'][1]['value']); } } diff --git a/tests/Unit/Output/Json/Task.php b/tests/Unit/Output/Json/Task.php index 7a5d1dc..cc3e42d 100644 --- a/tests/Unit/Output/Json/Task.php +++ b/tests/Unit/Output/Json/Task.php @@ -1,53 +1,52 @@ element($object); $this->assertSame('10-10-10-10', $result['uid']); $this->assertSame('task title', $result['summary']); $this->assertSame('2015-04-20T14:22:18Z', $result['created']); $this->assertSame('2015-04-20T14:22:18Z', $result['dtstamp']); $this->assertSame(0, $result['sequence']); $this->assertSame('PUBLIC', $result['class']); $this->assertSame("task description\nsecond line", $result['description']); $this->assertSame(56, $result['percent-complete']); $this->assertSame('German, Mark', $result['organizer']['parameters']['cn']); $this->assertSame('mailto:%3Cmark.german%40example.org%3E', $result['organizer']['cal-address']); $this->assertSame('text/plain', $result['attach'][0]['parameters']['fmttype']); $this->assertSame('test.txt', $result['attach'][0]['parameters']['x-label']); $this->assertSame('cid:test.1429539738.5833.txt', $result['attach'][0]['uri']); $this->assertSame('MAPI:PidLidTaskActualEffort', $result['x-custom'][0]['identifier']); $this->assertSame('8', $result['x-custom'][0]['value']); - $object = kolab_api_tests::get_data('20-20-20-20', md5('Tasks'), 'task', null, $context); + $object = kolab_api_tests::get_data('20-20-20-20', 'Tasks', 'task', null, $context); $result = $output->element($object); $this->assertSame('20-20-20-20', $result['uid']); $this->assertSame('task', $result['summary']); $this->assertSame('2015-04-20', $result['dtstart']); $this->assertSame('2015-04-27', $result['due']); $this->assertSame(array('freq' => 'DAILY'), $result['rrule']['recur']); $this->assertSame('NEEDS-ACTION', $result['status']); $this->assertSame('Manager, Jane', $result['attendee'][0]['parameters']['cn']); $this->assertSame('NEEDS-ACTION', $result['attendee'][0]['parameters']['partstat']); $this->assertSame('REQ-PARTICIPANT', $result['attendee'][0]['parameters']['role']); $this->assertSame(true, $result['attendee'][0]['parameters']['rsvp']); $this->assertSame('mailto:%3Cjane.manager%40example.org%3E', $result['attendee'][0]['cal-address']); - } } diff --git a/tests/data/data.json b/tests/data/data.json index 8d8559e..2bd546e 100644 --- a/tests/data/data.json +++ b/tests/data/data.json @@ -1,64 +1,72 @@ { "folders": { "INBOX": { "type": "mail.inbox", "items": ["1","2","5","6"] }, "Trash": { "type": "mail.wastebasket", "items": ["3","4"] }, "Drafts": { "type": "mail.drafts" }, "Sent": { "type": "mail.sentitems" }, "Junk": { "type": "mail.junkemail" }, "Calendar": { "type": "event.default", "items": ["100-100-100-100","101-101-101-101"] }, "Calendar/Personal Calendar": { "type": "event" }, "Contacts": { "type": "contact.default", "items": ["a-b-c-d"] }, "Files": { "type": "file.default" }, "Files2": { "type": "file" }, "Notes": { "type": "note.default", "items": ["1-1-1-1","2-2-2-2"] }, "Tasks": { "type": "task.default", "items":["10-10-10-10","20-20-20-20"] }, "Configuration": { - "type": "configuration" + "type": "configuration", + "items": ["98-98-98-98","99-99-99-99"] }, "Mail-Test": { "type": "mail" }, "Mail-Test2": { "type": "mail" } + }, + "tags": { + "tag1": { + "members": ["1", "10-10-10-10", "1-1-1-1", "a-b-c-d"] + }, + "tag2": { + } } } diff --git a/tests/index.php b/tests/index.php index f46daba..463be97 100644 --- a/tests/index.php +++ b/tests/index.php @@ -1,45 +1,46 @@ | | | | This program is free software: you can redistribute it and/or modify | | it under the terms of the GNU Affero General Public License as published | | by the Free Software Foundation, either version 3 of the License, or | | (at your option) any later version. | | | | This program is distributed in the hope that it will be useful, | | but WITHOUT ANY WARRANTY; without even the implied warranty of | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | GNU Affero General Public License for more details. | | | | You should have received a copy of the GNU Affero General Public License | | along with this program. If not, see | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ // environment initialization require_once __DIR__ . '/../lib/init.php'; try { $API = kolab_api::get_instance(); // If tests_username is set we use real Kolab server // otherwise use dummy backend class that simulates a real server if (!$API->config->get('tests_username')) { // Replace kolab_api_backend // @TODO: maybe we could replace kolab_storage and rcube_imap instead? require_once __DIR__ . '/lib/kolab_api_backend.php'; require_once __DIR__ . '/lib/kolab_api_message.php'; + require_once __DIR__ . '/lib/kolab_api_tests.php'; } $API->run(); } catch (Exception $e) { kolab_api::exception_handler($e); } diff --git a/tests/lib/kolab_api_backend.php b/tests/lib/kolab_api_backend.php index e52accd..9917c14 100644 --- a/tests/lib/kolab_api_backend.php +++ b/tests/lib/kolab_api_backend.php @@ -1,586 +1,668 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_backend { /** * Singleton instace of kolab_api_backend * * @var kolab_api_backend */ static protected $instance; public $delimiter = '/'; protected $db = array(); protected $folder = array(); protected $data = array(); /** * This implements the 'singleton' design pattern * * @return kolab_api_backend The one and only instance */ static function get_instance() { if (!self::$instance) { self::$instance = new kolab_api_backend; self::$instance->startup(); // init AFTER object was linked with self::$instance } return self::$instance; } /** * Class initialization */ public function startup() { $api = kolab_api::get_instance(); $db_file = $api->config->get('temp_dir') . '/tests.db'; if (file_exists($db_file)) { $db = file_get_contents($db_file); $this->db = unserialize($db); } $json = file_get_contents(__DIR__ . '/../data/data.json'); $this->data = json_decode($json, true); $this->folders = $this->parse_folders_list($this->data['folders']); + + if (!array_key_exists('tags', $this->db)) { + $this->db['tags'] = $this->data['tags']; + } } /** * Authenticate a user * * @param string Username * @param string Password * * @return bool */ public function authenticate($username, $password) { return true; } /** * Get list of folders * * @param string $type Folder type * * @return array|bool List of folders, False on backend failure */ public function folders_list($type = null) { return array_values($this->folders); } /** * Returns folder type * * @param string $uid Folder unique identifier * @param string $with_suffix Enable to not remove the subtype * * @return string Folder type */ public function folder_type($uid, $with_suffix = false) { $folder = $this->folders[$uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } $type = $folder['type'] ?: 'mail'; if (!$with_suffix) { list($type, ) = explode('.', $type); } return $type; } /** * Returns objects in a folder * * @param string $uid Folder unique identifier * * @return array Objects (of type rcube_message_header or kolab_format) * @throws kolab_api_exception */ public function objects_list($uid) { $folder = $this->folders[$uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } $result = array(); $is_mail = empty($folder['type']) || preg_match('/^mail/', $folder['type']); foreach ((array) $folder['items'] as $id) { $object = $this->object_get($uid, $id); if ($is_mail) { $object = $object->headers; } $result[] = $object; } return $result; } /** * Counts objects in a folder * * @param string $uid Folder unique identifier * * @return int Objects count * @throws kolab_api_exception */ public function objects_count($uid) { $folder = $this->folders[$uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } return count($folder['items']); } /** * Delete objects in a folder * * @param string $uid Folder unique identifier * @param string|array $set List of object IDs or "*" for all * * @throws kolab_api_exception */ public function objects_delete($uid, $set) { $folder = $this->folders[$uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } if ($set === '*') { $this->folders[$uid]['items'] = array(); $this->db['items'][$folder_uid] = array(); $result = true; } else { $this->folders[$uid]['items'] = array_values(array_diff($this->folders[$uid]['items'], $set)); foreach ($set as $i) { unset($this->folders[$uid]['items'][$i]); } } $this->db['folders'][$uid]['items'] = $this->folders[$uid]['items']; $this->save_db(); } /** * Get object data * * @param string $folder_uid Folder unique identifier * @param string $uid Object identifier * * @return rcube_message|array Object data * @throws kolab_api_exception */ public function object_get($folder_uid, $uid) { $folder = $this->folders[$folder_uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } if (!in_array($uid, (array) $folder['items'])) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } if ($data = $this->db['items'][$folder_uid][$uid]) { return $data; } list($type,) = explode('.', $folder['type']); $file = file_get_contents(__DIR__ . '/../data/' . $type . '/' . $uid); if (empty($file)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } // get message content and parse it $file = str_replace("\r?\n", "\r\n", $file); $params = array('uid' => $uid, 'folder' => $folder_uid); $object = new kolab_api_message($file, $params); + // get assigned tag-relations + $tags = array(); + foreach ($this->db['tags'] as $tag_name => $tag) { + if (in_array($uid, (array) $tag['members'])) { + $tags[] = $tag_name; + } + } + if ($type != 'mail') { $object = $object->to_array($type); + $object['categories'] = $tags; + } + else { + $object->categories = $tags; } return $object; } /** * Create an object * * @param string $folder_uid Folder unique identifier * @param string $data Object data * @param string $type Object type * * @throws kolab_api_exception */ public function object_create($folder_uid, $data, $type) { $folder = $this->folders[$folder_uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } /* if (strpos($folder['type'], $type) !== 0) { throw new kolab_api_exception(kolab_api_exception::INVALID_REQUEST); } */ $data['uid'] = microtime(true); + if (!empty($data['categories'])) { + foreach ($categories as $cat) { + if (!$this->db['tags'][$cat]) { + $this->db['tags'][$cat] = array(); + } + + if (!in_array($uid, (array) $this->db['tags'][$cat]['members'])) { + $this->db['tags'][$cat]['members'][] = $uid; + } + } + } + $this->folders[$folder_uid]['items'][] = $data['uid']; $this->db['folders'][$folder_uid]['items'] = $this->folders[$folder_uid]['items']; $this->db['items'][$folder_uid][$data['uid']] = $data; $this->save_db(); return $data['uid']; } /** * Update an object * * @param string $folder_uid Folder unique identifier * @param string $data Object data * @param string $type Object type * * @throws kolab_api_exception */ public function object_update($folder_uid, $data, $type) { $folder = $this->folders[$folder_uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } /* if (strpos($folder['type'], $type) !== 0) { throw new kolab_api_exception(kolab_api_exception::INVALID_REQUEST); } */ + + if (array_key_exists('categories', $data)) { + foreach ($this->db['tags'] as $tag_name => $tag) { + if (($idx = array_search($tag_name, (array) $data['categories'])) !== false) { + unset($data['categories'][$idx]); + continue; + } + + $this->db['tags'][$tag_name]['members'] = array_diff((array)$this->db['tags'][$tag_name]['members'], array($data['uid'])); + } + foreach ((array) $data['categories'] as $cat) { + $this->db['tags'][$cat] = array('members' => array($data['uid'])); + } + } + // remove _formatobj which is problematic in serialize/unserialize unset($data['_formatobj']); $this->db['items'][$folder_uid][$data['uid']] = $data; $this->save_db(); } /** * Get attachment body * * @param mixed $object Object data (from self::object_get()) * @param string $part_id Attachment part identifier * @param mixed $mode NULL to return a string, -1 to print body * or file pointer to save the body into * * @return string Attachment body if $mode=null * @throws kolab_api_exception */ public function attachment_get($object, $part_id, $mode = null) { + $msg_uid = is_array($object) ? $object['uid'] : $object->uid; + // object is a mail message if (!($object instanceof kolab_api_message)) { $object = $object['_message']; } + // check if it's not deleted + if (in_array($msg_uid . ":" . $part_id, (array) $this->db['deleted_attachments'])) { + throw new kolab_api_exception(kolab_api_exception::INVALID_REQUEST); + } + $body = $object->get_part_body($part_id); if (!$mode) { return $body; } else if ($mode === -1) { echo $body; } } + /** + * Delete an attachment from the message + * + * @param mixed $object Object data (from self::object_get()) + * @param string $id Attachment identifier + * + * @return boolean|string True or message UID (if changed) + * @throws kolab_api_exception + */ + public function attachment_delete($object, $id) + { + $msg_uid = is_array($object) ? $object['uid'] : $object->uid; + $key = $msg_uid . ":" . $part_id; + + // check if it's not deleted + if (in_array($key, (array) $this->db['deleted_attachments'])) { + throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); + } + + // object is a mail message + if (!($object instanceof kolab_api_message)) { + $object = $object['_message']; + } + + if ($object->get_part_body($id) === null) { + throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); + } + + $this->db['deleted_attachments'][] = $key; + $this->save_db(); + } + /** * Creates a folder * * @param string $name Folder name (UTF-8) * @param string $parent Parent folder identifier * @param string $type Folder type * * @return bool Folder identifier on success */ public function folder_create($name, $parent = null, $type = null) { $folder = $name; if ($parent) { $parent_folder = $this->folders[$parent]; if (!$parent_folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } $folder = $parent_folder['fullpath'] . $this->delimiter . $folder; } - $uid = md5($folder); + $uid = kolab_api_tests::folder_uid($folder, false); // check if folder exists if ($this->folders[$uid]) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } $this->folders[$uid] = array( 'name' => $name, 'fullpath' => $folder, - 'parent' => $parent ? md5($parent) : null, + 'parent' => $parent ? kolab_api_tests::folder_uid($parent, false) : null, 'uid' => $uid, 'type' => $type ? $type : 'mail', ); $this->db['folders'][$uid] = $this->folders[$uid]; $this->save_db(); return $uid; } /** * Updates a folder * * @param string $uid Folder identifier * @param array $updates Updates (array with keys type, subscribed, active) * * @throws kolab_api_exception */ public function folder_update($uid, $updates) { $folder = $this->folders[$uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } foreach ($updates as $idx => $value) { $this->db['folders'][$uid][$idx] = $value; $this->folders[$uid][$idx] = $value; } $this->save_db(); } /** * Renames/moves a folder * * @param string $old_name Folder name (UTF8) * @param string $new_name New folder name (UTF8) * * @throws kolab_api_exception */ public function folder_rename($old_name, $new_name) { - $old_uid = md5($old_name); - $new_uid = md5($new_name); + $old_uid = kolab_api_tests::folder_uid($old_name, false); + $new_uid = kolab_api_tests::folder_uid($new_name, false); $folder = $this->folders[$old_uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } if ($this->folders[$new_uid]) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } $path = explode($this->delimiter, $new_name); $folder['fullpath'] = $new_name; $folder['name'] = array_pop($path); unset($this->folders[$old_uid]); $this->folders[$new_uid] = $folder; $this->db['folders'][$new_uid] = $folder; $this->db['deleted'][] = $old_uid; $this->save_db(); } /** * Deletes folder * * @param string $uid Folder UID * * @return bool True on success, False on failure * @throws kolab_api_exception */ public function folder_delete($uid) { $folder = $this->folders[$uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } unset($this->folders[$uid]); $this->db['deleted'][] = $uid; $this->save_db(); } /** * Folder info * * @param string $uid Folder UID * * @return array Folder information * @throws kolab_api_exception */ public function folder_info($uid) { $folder = $this->folders[$uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } // some info is not very interesting here ;) unset($folder['items']); return $folder; } /** * Returns IMAP folder name with full path * * @param string $uid Folder identifier * * @return string Folder full path (UTF-8) */ public function folder_uid2path($uid) { if ($uid === null || $uid === '') { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } $folder = $this->folders[$uid]; if (!$folder) { throw new kolab_api_exception(kolab_api_exception::NOT_FOUND); } return $folder['fullpath']; } /** * Parse folders list into API format */ protected function parse_folders_list($list) { $folders = array(); foreach ($list as $path => $folder) { - $uid = md5($path); + $uid = kolab_api_tests::folder_uid($path, false); if (!empty($this->db['deleted']) && in_array($uid, $this->db['deleted'])) { continue; } if (strpos($path, $this->delimiter)) { $list = explode($this->delimiter, $path); $name = array_pop($list); $parent = implode($this->delimiter, $list); - $parent_id = md5($parent); + $parent_id = kolab_api_tests::folder_uid($parent, false); } else { $parent_id = null; $name = $path; } $data = array( 'name' => $name, 'fullpath' => $path, 'parent' => $parent_id, 'uid' => $uid, ); if (!empty($this->db['folders']) && !empty($this->db['folders'][$uid])) { $data = array_merge($data, $this->db['folders'][$uid]); } $folders[$uid] = array_merge($folder, $data); } foreach ((array) $this->db['folders'] as $uid => $folder) { if (!$folders[$uid]) { $folders[$uid] = $folder; } } // sort folders uasort($folders, array($this, 'sort_folder_comparator')); return $folders; } /** * Callback for uasort() that implements correct * locale-aware case-sensitive sorting */ protected function sort_folder_comparator($str1, $str2) { $path1 = explode($this->delimiter, $str1['fullpath']); $path2 = explode($this->delimiter, $str2['fullpath']); foreach ($path1 as $idx => $folder1) { $folder2 = $path2[$idx]; if ($folder1 === $folder2) { continue; } return strcoll($folder1, $folder2); } } /** * Save current database state */ protected function save_db() { $api = kolab_api::get_instance(); $db_file = $api->config->get('temp_dir') . '/tests.db'; $db = serialize($this->db); file_put_contents($db_file, $db); } } diff --git a/tests/lib/kolab_api_tests.php b/tests/lib/kolab_api_tests.php index 8f8692d..e0e540d 100644 --- a/tests/lib/kolab_api_tests.php +++ b/tests/lib/kolab_api_tests.php @@ -1,110 +1,131 @@ | | | | This program is free software: you can redistribute it and/or modify | | it under the terms of the GNU Affero General Public License as published | | by the Free Software Foundation, either version 3 of the License, or | | (at your option) any later version. | | | | This program is distributed in the hope that it will be useful, | | but WITHOUT ANY WARRANTY; without even the implied warranty of | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | GNU Affero General Public License for more details. | | | | You should have received a copy of the GNU Affero General Public License | | along with this program. If not, see | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_tests { /** * Reset backend state */ public static function reset_backend() { // @TODO: reseting real server $rcube = rcube::get_instance(); $temp_dir = $rcube->config->get('temp_dir'); $filename = $temp_dir . '/tests.db'; if (file_exists($filename)) { unlink($filename); } } /** * Initializes kolab_api_request object * * @param string Accepted response type (xml|json) * * @return kolab_api_request Request object */ public static function get_request($type, $suffix = '') { $rcube = rcube::get_instance(); $base_uri = $rcube->config->get('tests_uri', 'http://localhost/copenhagen-tests'); $username = $rcube->config->get('tests_username', 'test'); $password = $rcube->config->get('tests_password', 'test'); if ($suffix) { $base_uri .= $suffix; } $request = new kolab_api_request($base_uri, $username, $password); // set expected response type $request->set_header('Accept', $type == 'xml' ? 'application/xml' : 'application/json'); return $request; } /** * Get data object */ - public static function get_data($uid, $folder_uid, $type, $format = '', &$context = null) + public static function get_data($uid, $folder_name, $type, $format = '', &$context = null) { - $file = file_get_contents(__DIR__ . "/../data/$type/$uid"); + $file = file_get_contents(__DIR__ . "/../data/$type/$uid"); + $folder_uid = self::folder_uid($folder_name, false); // get message content and parse it $file = str_replace("\r?\n", "\r\n", $file); $params = array('uid' => $uid, 'folder' => $folder_uid); $object = new kolab_api_message($file, $params); if ($type != 'mail') { $object = $object->to_array($type); } $context = array( 'object' => $object, 'folder_uid' => $folder_uid, 'object_uid' => $uid, ); if ($format) { $model = self::get_output_class($format, $type); $object = $model->element($object); } return $object; } public static function get_output_class($format, $type) { // fake GET request to have proper API class in kolab_api::get_instance $_GET['request'] = "{$type}s"; $output = "kolab_api_output_{$format}"; $class = "{$output}_{$type}"; $output = new $output(kolab_api::get_instance()); $model = new $class($output); return $model; } + + /** + * Get folder UID by name + */ + public static function folder_uid($name, $api_test = true) + { + // @TODO: get real UID from IMAP when testing on a real server + // and $api_test = true + return md5($name); + } + + /** + * Build MAPI object identifier + */ + public static function mapi_uid($folder_name, $api_test, $msg_uid, $attachment_uid = null) + { + $folder_uid = self::folder_uid($folder_name, $api_test); + + return kolab_api_filter_mapistore::uid_encode($folder_uid, $msg_uid, $attachment_uid); + } }