Projet

Général

Profil

Révision 55670b15

Ajouté par Assos Assos il y a presque 10 ans

Weekly update of contrib modules

Voir les différences:

drupal7/sites/all/modules/date_ical/README.txt
2 2

  
3 3
This module allows users to export iCal feeds using Views, and import iCal feeds
4 4
from other sites using Feeds. Any entity that contains a Date field can act as
5
the source of events for an iCal feed.
5
the source/target to export/import an iCal feed.
6

  
6 7

  
7 8
===============================================================================
8 9
INSTALLATION
......
15 16
- The Feeds module is optional. It's needed only if you you wish to import iCal
16 17
  feeds from other sites.
17 18

  
18
To install the iCalcreator library, download it from the project's github:
19
http://github.com/iCalcreator/iCalcreator
20
Using either git clone or the "Download Zip" button, you'll find the file
21
iCalcreator.class.php inside. Copy that file to a folder in your Drupal site
22
named sites/all/libraries/iCalcreator.
19
To install the iCalcreator library, download the project's official zip file:
20
https://github.com/iCalcreator/iCalcreator/archive/master.zip
21
Extract it, and copy iCalcreator.class.php to a folder in your Drupal site
22
named sites/all/libraries/iCalcreator (you'll need to create that folder).
23 23

  
24
Or, if you have drush, install iCalcreator by running this command from your
25
site's root directory:
24
Or, if you have drush, you can install iCalcreator by running this command from
25
your site's root directory:
26 26
drush make sites/all/modules/date_ical/date_ical.make --no-core
27 27

  
28 28
Then, clear the cache on your site by using either "drush cc all" or logging in
......
56 56
    size, include additional information from other fields, etc.
57 57
4.  Do this for each of the content types that you wish to include in your
58 58
    site's iCal feeds.
59
5.  Create a new View that displays the entities that you want to include in the
60
    iCal feed.
61
6.  Add a "Feed" to the view. Change the Format to "iCal Feed". When you click
62
    Apply from that dialog, you'll be given the option to name the calendar,
63
    which will appear in your users' calendar clients as the calendar's title.
59
5.  Create a new View that displays the entities that you want to include in
60
    the iCal feed.
61
6.  Add a "Feed" display to the same View. Change the Format to "iCal Feed".
62
    When you click "Apply" from that dialog, you'll be given the option to name
63
    the calendar, which will appear in your users' calendar clients as the
64
    calendar's title.
64 65
7.  Change the Show setting to "iCal Entity".
65 66
8.  In the settings for iCal Entity, select the date field that should be used
66 67
    as the event date for the iCal feed. Make sure that you choose a field that
67 68
    is a part of every entity that your View displays. Otherwise, the entities
68 69
    which don't have that field will be left out of the iCal feed.
69
9.  You may optionally choose a field that will be used to populate the Location
70
    property of events in your iCal feed. This field can be a text field, a
71
    Node Reference field, an Addressfield, or a Location field.
72
10. Give the feed a path like 'calendar/%/export.ics', including a '/%/' for 
70
9.  You may optionally choose a field that will be used to populate the 
71
    Location property of events in your iCal feed. This field can be a text
72
    field, a Node Reference field, an Addressfield, or a Location field.
73
10. Give the Feed a path like 'calendar/%/export.ics', including a '/%/' for
73 74
    every contextual filter in the view.
74 75
11. Make sure the Pager options are set to "Display all items".
75 76
12. Add date filters or arguments that will constrain the view to the items you
76 77
    want to be included in the iCal feed.
77
13. Attach the feed to a another view (usually a Page view that is displaying
78
    the same events). Be aware, though, that attaching the feed to a view with
79
    different output will not make the iCal feed include that output. It will
80
    always include the events which match the feed's filters.
78
13. Using the "Attach to:" setting in the Feed Settings panel, attach the feed
79
    to a another display in the same view (usually a Page display). Be aware,
80
    though, that the Feed will display exactly what its settings tell it to,
81
    regardless of how the Page display is set up. Thus, it's best to ensure
82
    that both displays are configured to include the same content.
81 83
14. Save the View.
82
15. Navigate to a page which displays the attached view. You should see the iCal
83
    icon at the bottom of the view's output. Clicking on the icon will subscribe
84
    your preferred calendar app to the iCal feed. However, if you don't have a
85
    calendar app set up on your computer, you'll want to go back to the View
86
    settings page, click the Settings link next to "Format: iCal Feed", and check
87
    "Disable webcal://", then save your View. This will make the iCal icon
88
    download a .ics file with the events, instead of loading the events directly
89
    into a calendar app.
84
15. Navigate to a page which displays the view (usually the Page display's
85
    "path" setting). You should see the iCal icon at the bottom of the view's
86
    output. Clicking on the icon will subscribe your calendar app to the iCal
87
    feed.
88
16. If you don't have a calendar app set up on your computer, or you want your
89
    users to download the ical feed rather than subscribe to it, you'll want to
90
    go back to the View settings page, click the Settings link next to
91
    "Format: iCal Feed", and check "Disable webcal://". Then save your View.
92
    This will make the iCal icon download a .ics file with the events, instead
93
    of loading the events directly into the user's calendar app.
90 94

  
91 95
HOW TO EXPORT AN ICAL FEED USING THE iCal Fields PLUGIN
92 96
1-6.These steps are the same as above.
......
94 98
    your iCal feed with. A Date field is required, and fields that will act as
95 99
    the Title and Description of the events are reccomended. You can also
96 100
    include a Location field.
97
8.  Back in the FORMAT section, change the Show setting to 'iCal Fields'.
101
8.  Back in the FORMAT section, change the "Show" setting to 'iCal Fields'.
98 102
9.  In the settings for iCal Fields, choose which views fields you want to use
99 103
    for the Date, Title, Description, and Location.
100 104
10+ These steps are the same as above.
......
133 137
     you add any more mappings, click "Save" at the bottom of the page.
134 138
  2) It's a good idea to map the "Summary/Title" source to the "Title" target,
135 139
     and the "Description" source to whatever field is the "body" of the node.
136
  3) As of 2014/02/03 there is a major bug in Feeds that leaves the Date
137
     values on all imported events blank. You must update your Feeds module
138
     to the dev release (https://drupal.org/node/927032) to overcome this bug.
140
  3) AS OF 2014/04/10 THERE IS A MAJOR BUG IN Feeds WHICH LEAVES THE DATE
141
     VALUES ON ALL IMPORTED EVENTS BLACNK. YOU MUST APPLY A PATCH TO Feeds
142
     TO FIX THIS PROBLEM. IT IS AVAILABLE HERE: http://drupal.org/node/2237177.
139 143
- Once you've completed all the mappings, click the "Save" button on the
140 144
  bottom left side of the page.
141 145
- Now you can import the iCal feed into nodes by going to the /import page of
142 146
  your site (e.g. http://www.exmaple.com/import). Click the link for the
143
  importer you just created, and enter the URL of the feed you'd like to
144
  import into the "URL" field. Click the "Import" button, and observe the
145
  progress.
147
  importer you just created, and enter the URL of the feed into the "URL"
148
  field. Click the "Import" button, and observe the progress.
146 149
- Once it's done, you should see a green message saying "Created X nodes." If
147 150
  you do, you've successfully set up your iCal importer. If you get some other
148 151
  message, you'll need to tweak the importer's settings.
......
150 153
Remember, you have to map the UID source to the GUID target, and make it
151 154
unique, or your imports won't work!
152 155

  
153
IMPORTANT NOTE:
154
If you're building a site that will be viewed by out-of-state users, and you
155
allow said users to set their own timezone, you'll want to set up your Date
156
fields to use the "Date's time zone" option. If you don't, then users who live
157
in a different timezone will be shown the times for your events in their local
158
timezone, rather than your events' timezone. This makes sense if your events
159
will be broadcast live to these out-of-state users, but if they need to travel
160
to your event, they may end up arriving at the wrong time.
156

  
157
===============================================================================
158
IMPORTANT NOTE ABOUT THE DATE FIELD TIMEZONE SETTING
159
===============================================================================
160
Date fields have a setting called "Time zone handling" which determines how
161
dates are stored in the database, and how they are displayed to users.
162
 - "Site's time zone" converts the date to UTC as it stores it to the DB. Upon
163
  display, it converts the date to the "Default time zone" that's set on your
164
  site's Regional Settings configuration page (/admin/config/regional/settings).
165
 - "Date's time zone" stores the date as it is entered, along with the timezone
166
  name. Upon display, it converts the date from the stored timezone into the
167
  site's default timezone. Well, I'm pretty sure it's *supposed* to do that, but
168
  the code behind this setting is very buggy. DO NOT USE THIS SETTING.
169
 - "User's time zone" converts the date to UTC as it stores it to the DB. Upon
170
  display, it converts the date to the current user's timezone setting.
171
 - "UTC" converts the date to UTC as it stores it to the DB. Upon display, it
172
  performs no conversion, showing the UTC date directly to the user.
173
 - "No time zone conversion" performs no conversion as it stores the date in
174
  the DB. It also performs no conversion upon display.
175

  
176
The appropriate setting to choose here will depend upon how you want times to
177
be displayed on your site. The best setting *would* be "Date's time zone",
178
but since that setting is so buggy, I must recommend against it. Instead,
179
I'd suggest using "Site's time zone" for sites which host events that are
180
mostly in the same timezone (set the site's default timezone appropriately).
181
This works just right for local users of your site, and will be the least
182
confusing for users who live in a different timezone.
183

  
184
For sites which store events that take place in multiple different timezones,
185
the "User's time zone" setting is probably the most appropriate. Most users will
186
presumably be tuning in to your events online or on TV (since many take place
187
far away from them), which means they'll want to know what time the event occurs
188
in their local timezone, so they don't miss the broadcast.
189

  
190
If your Date field is already set to "Date's time zone", you won't be able to
191
change it, because that setting uses a different table schema than the others.
192
Since "Date's time zone" is very buggy, I'd strongly recomend deleting the
193
field and recreating it with a different setting. This will delete all the
194
dates in existing event nodes which use this field.
195

  
161 196

  
162 197
===============================================================================
163 198
HOW TO FIX THE "not a valid timezone" ERROR
......
184 219
Replace <module> with the name of your module, change the code to do whatever
185 220
needs to be done to fix your timezones, and clear your Drupal cache.
186 221

  
222

  
187 223
===============================================================================
188 224
ADDITIONAL NOTES
189 225
===============================================================================
190
Date iCal only supports outputting iCal calendars through Views.
226
Date iCal only supports exporting iCal calendars by using Views.
191 227
To put an "Add to calendar" button on individual event nodes, try the
192 228
Add to Cal module (http://drupal.org/project/addtocal), or follow the
193 229
instructions created by the estimable nmc at:
drupal7/sites/all/modules/date_ical/date_ical.api.php
139 139
 *****************************************************************************/
140 140

  
141 141
/**
142
 * Alter the vcalendar object created from an imported iCal feed.
142
 * Alter the vcalendar object imported from an iCal feed.
143 143
 *
144 144
 * @param object $calendar
145 145
 *   An instance of the iCalcreator library's vcalendar class.
......
153 153
}
154 154

  
155 155
/**
156
 * Alter a calendar component created from an imported iCal feed.
156
 * Alter a calendar component imported from an iCal feed.
157 157
 *
158 158
 * @param object $component
159 159
 *   This will usually be an iCalcreator vevent object, but Date iCal also
......
174 174
  }
175 175
}
176 176

  
177
/**
178
 * Alter the parsed data for an event imported from an iCal feed.
179
 *
180
 * @param array $data
181
 *   An associative array of field data that represents an imported event.
182
 * @param array $context
183
 *   An associative array of context, with the following keys and values:
184
 *   - 'calendar': The iCalcreator vcalendar parent object of this component.
185
 *   - 'source': FeedsSource object for this Feed.
186
 *   - 'fetcher_result': The FeedsFetcherResult object for this Feed.
187
 */
188
function hook_date_ical_import_post_parse_alter(&$data, $context) {
189
  // Example of what might be done with this alter hook.
190
  if (!empty($context['calendar']->xprop['X-WR-CALNAME']['value'])) {
191
    // Do something with the calendar name....
192
  }
193
}
194

  
177 195
/**
178 196
 * Alter the timezone string from an imported iCal Feed.
179 197
 *
drupal7/sites/all/modules/date_ical/date_ical.info
21 21
; Includes for iCal feed import using Feeds
22 22
files[] = includes/DateiCalFeedsParser.inc
23 23

  
24
; Information added by Drupal.org packaging script on 2014-02-04
25
version = "7.x-3.1"
24
; Information added by Drupal.org packaging script on 2014-05-30
25
version = "7.x-3.2"
26 26
core = "7.x"
27 27
project = "date_ical"
28
datestamp = "1391480015"
28
datestamp = "1401492228"
29 29

  
drupal7/sites/all/modules/date_ical/date_ical.module
10 10
 * value of the iCal feeds created by Date iCal. It's primarily used for
11 11
 * debugging.
12 12
 */
13
define('DATE_ICAL_VERSION', '3.1');
13
define('DATE_ICAL_VERSION', '3.2');
14 14

  
15 15
/**
16 16
 * Exception class for generic exceptions thrown by this module.
......
168 168
    'download url' => 'http://github.com/iCalcreator/iCalcreator',
169 169
    'version arguments' => array(
170 170
      'file' => 'iCalcreator.class.php',
171
      'pattern' => "/define\( 'ICALCREATOR_VERSION', 'iCalcreator ([\d\.]+)' \);/",
171
      'pattern' => "/define.*?ICALCREATOR_VERSION.*?([\d\.]+)/",
172 172
      'lines' => 100,
173 173
    ),
174 174
    'files' => array(
drupal7/sites/all/modules/date_ical/date_ical.utils.inc
42 42
  $start_datetime = date_format($start, DATE_FORMAT_DATETIME);
43 43
  
44 44
  if (!empty($rrule_values['UNTIL']['datetime'])) {
45
    // TODO: The spec says that UNTIL must be specified in UTC, but I think
46
    // this may not be followd by all feed creators. It may be a good idea to
47
    // support optionally assuming the date has the same TZID as DTSTART.
48
    $end = date_ical_date($rrule_values['UNTIL'], $timezone);
49
    $end_datetime = date_format($end, DATE_FORMAT_DATETIME);
45
    // The spec says that UNTIL must be in UTC, but not all feed creators
46
    // follow that rule. If the user specified that he wanted to overcome this
47
    // problem, use $timezone for the $final_repeat, and then convert the UNTIL
48
    // in the unparsed RRULE to UTC.
49
    if (!empty($source->importer->config['parser']['config']['until_not_utc'])) {
50
      // Change the parsed UNTIL from UTC to $timezone, so that the
51
      // date_ical_date() won't convert it.
52
      $rrule_values['UNTIL']['tz'] = $timezone;
53
      
54
      // Convert the unparsed UNTIL to UTC, since the Date code will use it.
55
      // It may currently have a Z on it, but only because iCalcreator blindly
56
      // adds one to DATETIME-type UNTILs if it's not there.
57
      $matches = array();
58
      if (preg_match('/^(.*?)UNTIL=([\dT]+)Z?(.*?)$/', $repeat_data['RRULE'], $matches)) {
59
        // If the UNTIL value doesn't have a "T", it's a DATE, making timezone
60
        // fixes irrelvant.
61
        if (strpos($matches[2], 'T') !== FALSE) {
62
          $until_date = new DateObject($matches[2], $timezone);
63
          $until_date->setTimezone(new DateTimeZone('UTC'));
64
          $matches[2] = $until_date->format('Ymd\THis');
65
          $repeat_data['RRULE'] = "{$matches[1]}UNTIL={$matches[2]}Z{$matches[3]}";
66
        }
67
      }
68
      else {
69
        watchdog('date_ical', 'The RRULE string "%rrule" could not be parsed to fix the UNTIL value. Date repeats may not be calculated correctly.',
70
          array('%rrule' => $repeat_data['RRULE']), WATCHDOG_WARNING
71
        );
72
      }
73
    }
74
    $final_repeat = date_ical_date($rrule_values['UNTIL'], $timezone);
75
    $final_repeat_datetime = date_format($final_repeat, DATE_FORMAT_DATETIME);
50 76
  }
51 77
  elseif (!empty($rrule_values['COUNT'])) {
52
    $end_datetime = NULL;
78
    $final_repeat_datetime = NULL;
53 79
  }
54 80
  else {
55
    // No UNTIL and no COUNT?
81
    // No UNTIL and no COUNT? This is an illegal RRULE.
56 82
    return array();
57 83
  }
58 84
  
......
69 95
    $date = date_ical_date($rdate, $timezone);
70 96
    $additions[] = date_format($date, 'Y-m-d');
71 97
  }
72
  // TODO: EXRULE.
98
  
99
  // TODO: EXRULEs.
73 100
  
74 101
  $date_repeat_compatible_rrule = "{$repeat_data['RRULE']}\n{$repeat_data['RDATE']}\n{$repeat_data['EXDATE']}";
75
  $calculated_dates = date_repeat_calc($date_repeat_compatible_rrule, $start_datetime, $end_datetime, $exceptions, $timezone, $additions);
102
  $calculated_dates = date_repeat_calc($date_repeat_compatible_rrule, $start_datetime, $final_repeat_datetime, $exceptions, $timezone, $additions);
76 103
  $repeat_dates = array();
77 104
  foreach ($calculated_dates as $delta => $date) {
78 105
    // date_repeat_calc always returns DATE_DATETIME dates, which is
......
114 141
      continue;
115 142
    }
116 143
    
117
    // These keys never have multiple values.
144
    // The following keys never have multiple values.
118 145
    if (in_array($key, array('UNTIL', 'FREQ', 'INTERVAL', 'COUNT', 'WKST'))) {
119 146
      if ($key == 'UNTIL') {
120 147
        // This is a function from the date_api module, not date_ical.
drupal7/sites/all/modules/date_ical/includes/DateiCalFeedsParser.inc
34 34
      throw new DateIcalException(t('Parsing the data from %url failed. Please ensure that this URL leads to a valid iCal feed.', array('%url' => $url)));
35 35
    }
36 36
    
37
    // Total hack to get around iCalcreator's mistreatment of UID "0".
38
    if (empty($calendar->components[0]->uid) || empty($calendar->components[0]->uid['value'])) {
39
      $calendar->components[0]->uid = array('value' => 'zero', 'params' => NULL);
40
    }
41
    
37 42
    // Allow modules to alter the vcalendar object before we interpret it.
38 43
    $context = array(
39 44
      'source' => $source,
......
69 74
  public function sourceDefaults() {
70 75
    return array(
71 76
      'indefinite_count' => $this->config['indefinite_count'],
77
      'until_not_utc' => $this->config['until_not_utc'],
78
      'skip_days' => $this->config['skip_days'],
72 79
    );
73 80
  }
74 81
  
......
78 85
  public function configDefaults() {
79 86
    return array(
80 87
      'indefinite_count' => '52',
88
      'until_not_utc' => FALSE,
89
      'skip_days' => NULL,
81 90
    );
82 91
  }
83 92
  
......
98 107
      '#description' => t('Indefinitely repeating events are not supported. The repeat count will instead be set to this number.'),
99 108
      '#default_value' => $this->config['indefinite_count'],
100 109
    );
110
    $form['until_not_utc'] = array(
111
      '#title' => t('RRULE UNTILs are not in UTC'),
112
      '#type' => 'checkbox',
113
      '#description' => t('Enable this setting if your reccuring events are not repeating the correct number of times. ' .
114
          'The iCal spec requires that the UNTIL value in an RRULE almost always be specified in UTC, but some iCal feed creators fail to follow that rule ' .
115
          '(the UNTIL values in those feeds\' RRULEs don\'t end is "Z"). This causes the UNTIL value to be off by several hours, ' .
116
          'which can cause the repeat calculator to miss or add repeats.'),
117
      '#default_value' => $this->config['until_not_utc'],
118
    );
119
    $form['skip_days'] = array(
120
      '#title' => t('Skip events more than X days old'),
121
      '#type' => 'textfield',
122
      '#size' => 5,
123
      '#description' => t('Set this value to any positive integer (or 0) to skip events which ended more than that many days before the import. ' .
124
        'Leave it blank to import all events.'),
125
      '#default_value' => $this->config['skip_days'],
126
    );
101 127
    return $form;
102 128
  }
103 129
  
130
  /**
131
   * Validation handler for configForm.
132
   */
133
  public function configFormValidate(&$source_config) {
134
    if (!preg_match('/^\d+$/', $source_config['skip_days']) && $source_config['skip_days'] !== '') {
135
      form_set_error('skip_days', 'You must enter a positive integer.');
136
    }
137
    if ($source_config['skip_days'] === '') {
138
      $source_config['skip_days'] = NULL;
139
    }
140
  }
141
  
104 142
  /**
105 143
   * Creates the list of mapping sources offered by DateiCalFeedsParser.
106 144
   */
......
127 165
      'date_ical_parse_handler' => 'parseDateTimeProperty',
128 166
    );
129 167
    $sources['RRULE'] = array(
130
      'name' => t('Repeat Rule'),
168
      'name' => t('Date: Repeat Rule'),
131 169
      'description' => t('The RRULE property. Describes when and how often this event should repeat.
132 170
        The date field for the target node must be configured to support repeating dates, using the Date Repeat Field module (a submodule of Date).'),
133 171
      'date_ical_parse_handler' => 'parseRepeatProperty',
drupal7/sites/all/modules/date_ical/includes/date_ical_plugin_style_ical_feed.inc
410 410
      // Prevent devel module from appending queries to ical export.
411 411
      $GLOBALS['devel_shutdown'] = FALSE;
412 412
      
413
      drupal_add_http_header('Content-Type', 'text/calendar; charset=utf-8');
413
      drupal_add_http_header('Content-Type', 'text/calendar; charset=UTF-8');
414
      drupal_add_http_header('Cache-Control', 'no-cache, must-revalidate');
415
      drupal_add_http_header('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT');
414 416
      
415 417
      // For sites with Clean URLs disabled, the Display's "path" value ends
416 418
      // up only in the query args, meaning the filename won't be set properly
drupal7/sites/all/modules/date_ical/libraries/ParserVcalendar.inc
16 16
  protected $timezones = array();
17 17
  protected $xtimezone;
18 18
  
19
  /**
20
   * The parsed data for the component that's currently being processed.
21
   *
22
   * ParserVcalendar parses one component at a time. This array is stored as a
23
   * property so that each handler can tell what work the previous handlers
24
   * have already completed on the current component.
25
   *
26
   * @var array
27
   */
28
  protected $parsed_data = array();
29
  
19 30
  /**
20 31
   * Variables used for batch processing.
21 32
   */
......
28 39
  public function __construct($calendar, $source, $fetcher_result, $config) {
29 40
    $this->calendar = $calendar;
30 41
    $this->source = $source;
42
    $this->mapping_sources = feeds_importer($source->id)->parser->getMappingSources();
31 43
    $this->fetcherResult = $fetcher_result;
32 44
    $this->config = $config;
33 45
  }
34

  
46
  
35 47
  /**
36 48
   * Parses the vcalendar object into an array of event data arrays.
37 49
   *
......
42 54
   *   Specifies how many components to parse on this run.
43 55
   *
44 56
   * @return array
45
   *   An array of parsed event data keyed by the same strings as the array
46
   *   returned by DateiCalFeedsParser::getiCalMappingSources().
57
   *   An array of parsed event data keyed by our mapping source property keys.
47 58
   */
48 59
  public function parse($offset, $limit) {
49 60
    // Sometimes, the feed will set a timezone for every event in the calendar
......
69 80
      $this->timezones[] = $component;
70 81
    }
71 82
    
83
    // This content array is used by date_ical_import_component_alter() and
84
    // date_ical_import_parsed_data_alter().
85
    $context2 = array(
86
      'calendar' => $this->calendar,
87
      'source' => $this->source,
88
      'fetcher_result' => $this->fetcherResult,
89
    );
90
    
72 91
    // Collect each component, so we can batch them properly in the next loop.
73 92
    $raw_components = array();
74 93
    $types = array('VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY', 'VALARM');
......
76 95
      while ($vcalendar_component = $this->calendar->getComponent($type)) {
77 96
        // Allow modules to alter the vcalendar component before we parse it
78 97
        // into a Feeds-compatible data array.
79
        $context = array(
80
          'calendar' => $this->calendar,
81
          'source' => $this->source,
82
          'fetcher_result' => $this->fetcherResult,
83
        );
84
        drupal_alter('date_ical_import_component', $vcalendar_component, $context);
98
        drupal_alter('date_ical_import_component', $vcalendar_component, $context2);
85 99
        $raw_components[] = $vcalendar_component;
86 100
      }
87 101
    }
......
92 106
    // Parse each raw component in the current batch into a Feeds-compatible
93 107
    // event data array.
94 108
    $events = array();
95
    $sources = DateiCalFeedsParser::getiCalMappingSources();
96 109
    $batch = array_slice($raw_components, $offset, $limit, TRUE);
97 110
    foreach ($batch as $ndx => $raw_component) {
98
      $parsed_component = array();
99
      foreach ($sources as $property_key => $data) {
100
        $handler = $data['date_ical_parse_handler'];
101
        $parsed_component[$property_key] = $this->$handler($property_key, $raw_component);
111
      $this->parsed_data = array();
112
      foreach ($this->mapping_sources as $property_key => $data) {
113
        $handler = NULL;
114
        if (isset($data['date_ical_parse_handler'])) {
115
          $handler = $data['date_ical_parse_handler'];
116
        }
117
        else {
118
          // This is not one of our sources, so if we don't recognize and
119
          // support it, we'll have to pass a warning to the user.
120
          if ($property_key == 'geofield') {
121
            $handler = 'parseGeofield';
122
          }
123
          else {
124
            // We can safely ignore certain sources.
125
            $known_unknowns = array(
126
              // "Black Source 1" is from Feeds Tamper.
127
              'Blank source 1',
128
            );
129
            if (!in_array($property_key, $known_unknowns)) {
130
              // Only warn the user if this mapping source is in use.
131
              foreach ($this->source->importer->processor->config['mappings'] as $mapping) {
132
                if ($mapping['source'] == $property_key) {
133
                  drupal_set_message(t('Date iCal does not recognize the "@name" Mapping Source, and must skip it.', array('@name' => $data['name'])), 'warning', FALSE);
134
                  break;
135
                }
136
              }
137
            }
138
          }
139
        }
140
        if ($handler) {
141
          $this->parsed_data[$property_key] = $this->$handler($property_key, $raw_component);
142
        }
143
        
144
        if ($property_key == 'geofield' && !empty($this->parsed_data['geofield'])) {
145
          // To make our data readable by geofield_feeds_combined_source(), we
146
          // need to put it into the format output by Simplepie 1.3.
147
          $this->parsed_data['location_latitude'] = array($this->parsed_data['geofield']['lat']);
148
          $this->parsed_data['location_longitude'] = array($this->parsed_data['geofield']['lon']);
149
        }
150
      }
151
      
152
      // Allow modules to alter the final parsed data before we send it to the
153
      // Feeds processor.
154
      drupal_alter('date_ical_import_post_parse', $this->parsed_data, $context2);
155
      
156
      // Skip this event if it's earlier than the user's specified skip time.
157
      if (!$this->_skip_current_event()) {
158
        $events[] = $this->parsed_data;
102 159
      }
103
      $events[] = $parsed_component;
104 160
      // The indices of the original $raw_components array are preserved in
105 161
      // $batch, so using the $ndx value here lets us communicate our progress
106 162
      // through the full collection of components.
......
125 181
  }
126 182
  
127 183
  /**
128
   * Parses text fields.
184
   * Handler that parses text fields.
129 185
   *
130 186
   * @return string
131 187
   *   The parsed text property.
......
144 200
    $text = str_replace(array('\n', '\N'), "\n", $text);
145 201
    return $text;
146 202
  }
147

  
203
  
148 204
  /**
149
   * Parses field parameters.
205
   * Handler that parses GEO fields.
206
   *
207
   * @return array
208
   *   The latitude and longitude values, keyed by 'lat' and 'lon'.
209
   */
210
  public function parseGeofield($property_key, $vcalendar_component) {
211
    $geo = array();
212
    if (!empty($vcalendar_component->geo['value'])) {
213
      $geo['lat'] = $vcalendar_component->geo['value']['latitude'];
214
      $geo['lon'] = $vcalendar_component->geo['value']['longitude'];
215
    }
216
    return $geo;
217
  }
218
  
219
  /**
220
   * Handler that parses field parameters.
150 221
   *
151 222
   * @return string
152 223
   *   The parsed field parameter.
......
158 229
      // If the component doesn't have this property, return NULL.
159 230
      return NULL;
160 231
    }
161
    return isset($property['params'][$attr]) ? $property['params'][$attr] : '';
232
    $param = isset($property['params'][$attr]) ? $property['params'][$attr] : '';
233
    return $param;
162 234
  }
163

  
235
  
164 236
  /**
165
   * Parses DATE-TIME and DATE fields.
237
   * Handler that parses DATE-TIME and DATE fields.
166 238
   *
167 239
   * @return FeedsDateTime
168 240
   *   The parsed datetime object.
......
199 271
          // If this is an all-day event with no end or duration, treat this
200 272
          // as a single-day event by emulating DTEND as 1 day after DTSTART.
201 273
          $property = $dtstart;
202
          $property['value']['day'] = $dtstart['value']['day'] + 1;
274
          $property['value'] = iCalUtilityFunctions::_duration2date($property['value'], array('day' => 1));
203 275
        }
204 276
        else {
205 277
          // This event has no end date.
......
239 311
          $property['value'] = $prev_day;
240 312
        }
241 313
      }
242

  
314
      
243 315
      // FeedsDateTime->setTimezone() ignores timezone changes made to dates
244 316
      // with no time element, which means we can't compensate for the Date
245 317
      // module's automatic timezone conversion when it writes to the DB. To
......
290 362
        $datetimezone = new DateTimeZone(date_default_timezone_get());
291 363
      }
292 364
    }
293

  
294
    return new FeedsDateTime($date_string, $datetimezone);
365
    
366
    $datetime = new FeedsDateTime($date_string, $datetimezone);
367
    return $datetime;
295 368
  }
296

  
369
  
297 370
  /**
298
   * Parses multi-value fields, like the CATEGORIES component.
371
   * Handler that parses multi-value fields, like the CATEGORIES component.
299 372
   *
300 373
   * @return array
301 374
   *   An array of strings contaning the individual values.
......
316 389
    }
317 390
    return $property;
318 391
  }
319

  
392
  
320 393
  /**
321
   * Format RRULEs, which specify when and how often the event is repeated.
394
   * Handler that parses RRULE, RDATE, EXRULE, and EXDATE together.
322 395
   *
323 396
   * @return string
324
   *   An RRULE string, with EXDATE and RDATE values separated by \n.
325
   *   This is to make the RRULE compatible with date_repeat_split_rrule().
397
   *   The RRULE, RDATE, EXRULE, and EXDATE values concatinated with |.
326 398
   */
327 399
  public function parseRepeatProperty($property_key, $vcalendar_component) {
328 400
    if ($vcalendar_component->getProperty($property_key) === FALSE) {
329 401
      return NULL;
330 402
    }
331

  
403
    
404
    $uid = $vcalendar_component->getProperty('UID');
405
    $count = $this->config['indefinite_count'];
332 406
    // Due to a few bugs and limitations with Date Repeat, we need to massage
333 407
    // the RRULE a bit.
334 408
    if (count($vcalendar_component->rrule) > 1) {
335
      drupal_set_message(t('The event with UID %uid has multiple RRULEs, but the Date Repeat module only supports one. Only the first RRULE in the event will be used.<br>
336
          If your events need to have a complex repeat pattern, using RDATEs should help.',
337
        array('%uid' => $vcalendar_component->getProperty('UID'))), 'warning'
338
      );
409
      $msg = 'The event with UID %uid has multiple RRULEs, but the Date Repeat module only supports one. Only the first RRULE in the event will be used.
410
        If your events need to have a complex repeat pattern, using RDATEs should help.';
411
      watchdog('date_ical', $msg, array('%uid' => $uid), 'warning');
412
      drupal_set_message('At least one of the events in this iCal feed has multiple RRULEs, but the Date Repeat module only supports one.
413
        Only the first RRULE in an event will be used.', 'warning', FALSE);
414
      
339 415
      // Date Repeat will get extremely confused if it's sent multiple RRULE
340 416
      // values, so we need to manually pare it down to only the first one.
341 417
      $vcalendar_component->rrule = array($vcalendar_component->rrule[0]);
......
345 421
      if (!isset($rrule_data['value']['INTERVAL'])) {
346 422
        $rrule_data['value']['INTERVAL'] = '1';
347 423
      }
348

  
424
      
349 425
      if (!isset($rrule_data['value']['COUNT']) && !isset($rrule_data['value']['UNTIL'])) {
350
        drupal_set_message(t("The event with UID %uid has an indefinitely repeating RRULE, which the Date Repeat module doesn't support.<br>
426
        $msg = "The event with UID %uid has an indefinitely repeating RRULE, which the Date Repeat module doesn't support.
427
          As a workaround, Date iCal set the repeat count to @count. This value can be customized in the iCal parser settings.";
428
        watchdog('date_ical', $msg, array('%uid' => $uid, '@count' => $count), WATCHDOG_WARNING);
429
        drupal_set_message(
430
          t("At least one of the events in this iCal feed has an indefinitely repeating RRULE, which the Date Repeat module doesn't support.<br>
351 431
            As a workaround, Date iCal set the repeat count to @count. This value can be customized in the iCal parser settings.",
352
          array('%uid' => $vcalendar_component->getProperty('UID'), '@count' => $this->config['indefinite_count'])), 'warning'
432
          array('@count' => $count)),
433
          'warning',
434
          FALSE
353 435
        );
354 436
        $rrule_data['value']['COUNT'] = $this->config['indefinite_count'];
355 437
      }
356 438
    }
357

  
439
    
358 440
    $rrule = trim($vcalendar_component->createRrule());
359 441
    $rdate = trim($vcalendar_component->createRdate());
360 442
    $exrule = trim($vcalendar_component->createExrule());
361 443
    $exdate = trim($vcalendar_component->createExdate());
362 444
    return "$rrule|$rdate|$exrule|$exdate";
363 445
  }
364

  
446
  
365 447
  /**
366 448
   * Internal helper function for creating DateTimeZone objects.
367 449
   */
......
377 459
      $windows_to_olson_map = array();
378 460
      foreach ($zones_assoc['supplemental']['windowsZones']['mapTimezones'] as $mapTimezone) {
379 461
        if ($mapTimezone['mapZone']['_other'] == $tzid) {
380
          // $mapTimezone['mapZone']['_type'] is space-separated TZIDs.
462
          // Parse out the space-separated TZIDs from $mapTimezone['mapZone']['_type'].
381 463
          $tzids = preg_split('/\s/', $mapTimezone['mapZone']['_type']);
382 464
          try {
383 465
            // They all have the same UTC offset, so for our purposes we can
......
405 487
    }
406 488
    return $datetimezone;
407 489
  }
490
  
491
  /**
492
   * Internal helper function for skipping old events.
493
   */
494
  protected function _skip_current_event() {
495
    // Must use !isset() here, because 0 and NULL mean different things.
496
    if (!isset($this->config['skip_days'])) {
497
      return FALSE;
498
    }
499
    $compare_date = isset($this->parsed_data['DTEND']) ? $this->parsed_data['DTEND'] : $this->parsed_data['DTSTART'];
500
    $skip_date = new FeedsDateTime("today -{$this->config['skip_days']} days", $compare_date->getTimezone());
501
    $skip = ($skip_date > $compare_date);
502
    return $skip;
503
  }
408 504
}
drupal7/sites/all/modules/date_ical/tests/basic_tests.ics
132 132
DESCRIPTION:This event uses a fake TZID and should throw the "not a valid timezone" warning at import time, and be treated as UTC.
133 133
END:VEVENT
134 134

  
135
BEGIN:VEVENT
136
SUMMARY:Event w/ GEO
137
DTSTART;TZID=America/New_York:20131009T190000
138
DTEND;TZID=America/New_York:20131009T210000
139
UID:date_ical_basic_test0E
140
DESCRIPTION:This is a standard event that has a GEO field.
141
GEO:34.1378534;-118.1252851
142
END:VEVENT
143

  
135 144
END:VALENDAR
drupal7/sites/all/modules/date_ical/tests/until_tests.ics
1
BEGIN:VCALENDAR
2
PRODID:-//Google Inc//Google Calendar 70.9054//EN
3
VERSION:2.0
4
CALSCALE:GREGORIAN
5
METHOD:PUBLISH
6
X-WR-CALNAME:Events Feed
7
X-WR-TIMEZONE:America/New_York
8
X-WR-CALDESC:A calendar for the events feed
9

  
10
BEGIN:VTIMEZONE
11
TZID:America/New_York
12
X-LIC-LOCATION:America/New_York
13
BEGIN:DAYLIGHT
14
TZOFFSETFROM:-0500
15
TZOFFSETTO:-0400
16
TZNAME:EDT
17
DTSTART:19700308T020000
18
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
19
END:DAYLIGHT
20
BEGIN:STANDARD
21
TZOFFSETFROM:-0400
22
TZOFFSETTO:-0500
23
TZNAME:EST
24
DTSTART:19701101T020000
25
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
26
END:STANDARD
27
END:VTIMEZONE
28

  
29
BEGIN:VEVENT
30
SUMMARY:Event w/ Bad UNTIL
31
UID:12345acbdef1
32
DTSTART;TZID=America/Los_Angeles:20140323T190000
33
DTEND;TZID=America/Los_Angeles:20140323T210000
34
RRULE:FREQ=DAILY;UNTIL=20140328T190000;WKST=SU
35
DESCRIPTION:description
36
END:VEVENT
37

  
38
BEGIN:VEVENT
39
SUMMARY:Event w/ UTC UNTIL
40
UID:12345acbdef2
41
DTSTART;TZID=America/Los_Angeles:20140323T190000
42
DTEND;TZID=America/Los_Angeles:20140323T210000
43
RRULE:FREQ=DAILY;UNTIL=20140328T230000Z;WKST=SU
44
DESCRIPTION:description
45
END:VEVENT
46

  
47
BEGIN:VEVENT
48
SUMMARY:Event w/ COUNT
49
UID:12345acbdef3
50
DTSTART;TZID=America/Los_Angeles:20140323T190000
51
DTEND;TZID=America/Los_Angeles:20140323T210000
52
RRULE:FREQ=DAILY;COUNT=6;WKST=SU
53
DESCRIPTION:description
54
END:VEVENT
55

  
56
BEGIN:VEVENT
57
SUMMARY:Event w/ DATE-type UNTIL
58
UID:12345acbdef4
59
DTSTART;VALUE=DATE:20140323
60
DTEND;VALUE=DATE:20140323
61
RRULE:FREQ=DAILY;UNTIL=20140328;WKST=SU
62
DESCRIPTION:description
63
END:VEVENT
64

  
65
END:VALENDAR
drupal7/sites/all/modules/honeypot/honeypot.info
6 6

  
7 7
files[] = honeypot.test
8 8

  
9
; Information added by Drupal.org packaging script on 2013-12-14
10
version = "7.x-1.16"
9
; Information added by Drupal.org packaging script on 2014-05-30
10
version = "7.x-1.17"
11 11
core = "7.x"
12 12
project = "honeypot"
13
datestamp = "1386996205"
13
datestamp = "1401478128"
14 14

  
drupal7/sites/all/modules/honeypot/honeypot.module
91 91
  }
92 92
}
93 93

  
94
/**
95
 * Implements hook_trigger_info().
96
 */
97
function honeypot_trigger_info() {
98
  return array(
99
    'honeypot' => array(
100
      'honeypot_reject' => array(
101
        'label' => t('Honeypot rejection'),
102
      ),
103
    ),
104
  );
105
}
106

  
107
/**
108
 * Implements hook_rules_event_info()
109
 */
110
function honeypot_rules_event_info() {
111
  return array(
112
    'honeypot_reject' => array(
113
      'label' => t('Honeypot rejection'),
114
      'group' => t('Honeypot'),
115
      'variables' => array(
116
        'form_id' => array(
117
          'type' => 'text',
118
          'label' => t('Form ID of the form the user was disallowed from submitting.'),
119
        ),
120
        // Don't provide 'uid' in context because it is available as
121
        // site:current-user:uid.
122
        'type' => array(
123
          'type' => 'text',
124
          'label' => t('String indicating the reason the submission was blocked.'),
125
        ),
126
      ),
127
    ),
128
  );
129
}
130

  
94 131
/**
95 132
 * Build an array of all the protected forms on the site, by form_id.
96 133
 *
......
223 260
  // If not, throw an error.
224 261
  if (time() < ($honeypot_time + $time_limit)) {
225 262
    _honeypot_log($form_state['values']['form_id'], 'honeypot_time');
226
    $time_limit = honeypot_get_time_limit();
263
    // Get the time limit again, since it increases after first failure.
264
    $time_limit = honeypot_get_time_limit($form_state['values']);
227 265
    $form_state['values']['honeypot_time'] = time();
228 266
    form_set_error('', t('There was a problem with your form submission. Please wait @limit seconds and try again.', array('@limit' => $time_limit)));
229 267
  }
......
275 313
      ))->fetchField();
276 314
    }
277 315
    // Don't add more than 30 days' worth of extra time.
278
    $honeypot_time_limit = $honeypot_time_limit + (int) min($honeypot_time_limit + exp($number), 2592000);
316
    $honeypot_time_limit = (int) min($honeypot_time_limit + exp($number) - 1, 2592000);
279 317
    $additions = module_invoke_all('honeypot_time_limit', $honeypot_time_limit, $form_values, $number);
280 318
    if (count($additions)) {
281 319
      $honeypot_time_limit += array_sum($additions);
......
313 351

  
314 352
  // Allow other modules to react to honeypot rejections.
315 353
  module_invoke_all('honeypot_reject', $form_id, $user->uid, $type);
354

  
355
  // Trigger honeypot_reject action.
356
  if (module_exists('trigger')) {
357
    $aids = trigger_get_assigned_actions('honeypot_reject');
358
    $context = array(
359
      'group' => 'honeypot',
360
      'hook' => 'honeypot_reject',
361
      'form_id' => $form_id,
362
      // Do not provide $user in context because it is available as a global.
363
      'type' => $type,
364
    );
365
    // Honeypot does not act on any specific object.
366
    $object = NULL;
367
    actions_do(array_keys($aids), $object, $context);
368
  }
369

  
370
  // Trigger rules honeypot_reject event.
371
  if (module_exists('rules')) {
372
    rules_invoke_event('honeypot_reject', $form_id, $type);
373
  }
316 374
}
drupal7/sites/all/modules/honeypot/honeypot.test
98 98
    $this->drupalPost('user/register', $edit, t('Create new account'));
99 99

  
100 100
    // Form should have error message.
101
    $this->assertText(t('There was a problem with your form submission. Please wait'), 'Registration form protected by time limit.');
101
    $this->assertText(t('There was a problem with your form submission. Please wait 6 seconds and try again.'), 'Registration form protected by time limit.');
102 102
  }
103 103

  
104 104
  /**
......
170 170
    $this->assertNoText(t('There was a problem with your form submission.'), 'Honeypot not blocking node form previews.');
171 171
  }
172 172
}
173

  
174
/**
175
 * Test the functionality of the Honeypot module's integration with Trigger.
176
 */
177
class HoneypotTriggerTestCase extends DrupalWebTestCase {
178
  public static function getInfo() {
179
    return array(
180
      'name' => 'Honeypot Trigger integration',
181
      'description' => 'Ensure that Honeypot triggers events correctly.',
182
      'group' => 'Form API',
183
    );
184
  }
185

  
186
  public function setUp() {
187
    // Enable modules required for this test.
188
    parent::setUp(array('honeypot', 'trigger'));
189

  
190
    // Set up required Honeypot variables.
191
    variable_set('honeypot_element_name', 'url');
192
    // Disable time_limit protection.
193
    variable_set('honeypot_time_limit', 0);
194
    // Test protecting all forms.
195
    variable_set('honeypot_protect_all_forms', TRUE);
196
    variable_set('honeypot_log', FALSE);
197

  
198
    // Set up other required variables.
199
    variable_set('user_email_verification', TRUE);
200
    variable_set('user_register', USER_REGISTER_VISITORS);
201

  
202
    // Assign new action to Honeypot form rejection Trigger.
203
    db_insert('trigger_assignments')
204
      ->fields(array(
205
        'hook' => 'honeypot_reject',
206
        'aid' => 'system_block_ip_action',
207
        'weight' => 1,
208
      ))
209
      ->execute();
210
  }
211

  
212
  /**
213
   * Test trigger integration.
214
   */
215
  public function testHoneypotTriggerIntegration() {
216
    // Set up form and submit it.
217
    $edit['name'] = $this->randomName();
218
    $edit['mail'] = $edit['name'] . '@example.com';
219
    $edit['url'] = 'http://www.example.com/';
220
    $this->drupalPost('user/register', $edit, t('Create new account'));
221

  
222
    // Make sure Honeypot is working.
223
    $this->assertText(t('There was a problem with your form submission.'), 'Honeypot working correctly.');
224

  
225
    // Visit the home page and make sure the user is banned.
226
    $this->drupalGet('node');
227
    $this->assertText(t('has been banned'), 'User banned successfully.');
228
  }
229
}

Formats disponibles : Unified diff