CommunityMessages.php 7.04 KB
Newer Older
1
2
3
<?php
/*
 +--------------------------------------------------------------------+
Kurund Jalmi's avatar
Kurund Jalmi committed
4
 | CiviCRM version 4.7                                                |
5
 +--------------------------------------------------------------------+
colemanw's avatar
colemanw committed
6
 | Copyright CiviCRM LLC (c) 2004-2015                                |
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 +--------------------------------------------------------------------+
 | This file is a part of CiviCRM.                                    |
 |                                                                    |
 | CiviCRM is free software; you can copy, modify, and distribute it  |
 | under the terms of the GNU Affero General Public License           |
 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
 |                                                                    |
 | CiviCRM 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 and the CiviCRM Licensing Exception along                  |
 | with this program; if not, contact CiviCRM LLC                     |
 | at info[AT]civicrm[DOT]org. If you have questions about the        |
 | GNU Affero General Public License or the licensing of CiviCRM,     |
 | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
 +--------------------------------------------------------------------+
26
 */
27
28
29
30
31
32

/**
 * Manage the download, validation, and rendering of community messages
 */
class CRM_Core_CommunityMessages {

33
  const DEFAULT_MESSAGES_URL = 'https://alert.civicrm.org/alert?prot=1&ver={ver}&uf={uf}&sid={sid}&lang={lang}&co={co}';
34
  const DEFAULT_PERMISSION = 'administer CiviCRM';
35

36
  /**
37
   * Default time to wait before retrying.
38
39
40
41
42
43
44
45
46
47
48
49
50
   */
  const DEFAULT_RETRY = 7200; // 2 hours

  /**
   * @var CRM_Utils_HttpClient
   */
  protected $client;

  /**
   * @var CRM_Utils_Cache_Interface
   */
  protected $cache;

51
52
53
54
55
  /**
   * @var FALSE|string
   */
  protected $messagesUrl;

56
  /**
57
   * Create default instance.
58
59
60
61
62
63
64
65
66
67
68
69
70
   *
   * @return CRM_Core_CommunityMessages
   */
  public static function create() {
    return new CRM_Core_CommunityMessages(
      new CRM_Utils_Cache_SqlGroup(array(
        'group' => 'community-messages',
        'prefetch' => FALSE,
      )),
      CRM_Utils_HttpClient::singleton()
    );
  }

71
72
73
  /**
   * @param CRM_Utils_Cache_Interface $cache
   * @param CRM_Utils_HttpClient $client
74
   * @param null $messagesUrl
75
   */
76
  public function __construct($cache, $client, $messagesUrl = NULL) {
77
78
    $this->cache = $cache;
    $this->client = $client;
79
    if ($messagesUrl === NULL) {
80
      $this->messagesUrl = Civi::settings()->get('communityMessagesUrl');
81
82
83
84
    }
    else {
      $this->messagesUrl = $messagesUrl;
    }
85
86
87
    if ($this->messagesUrl === '*default*') {
      $this->messagesUrl = self::DEFAULT_MESSAGES_URL;
    }
88
89
90
  }

  /**
91
   * Get the messages document (either from the cache or by downloading)
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
   *
   * @return NULL|array
   */
  public function getDocument() {
    $isChanged = FALSE;
    $document = $this->cache->get('communityMessages');

    if (empty($document) || !is_array($document)) {
      $document = array(
        'messages' => array(),
        'expires' => 0, // ASAP
        'ttl' => self::DEFAULT_RETRY,
        'retry' => self::DEFAULT_RETRY,
      );
      $isChanged = TRUE;
    }

    if ($document['expires'] <= CRM_Utils_Time::getTimeRaw()) {
110
      $newDocument = $this->fetchDocument();
totten's avatar
totten committed
111
      if ($newDocument && $this->validateDocument($newDocument)) {
112
113
        $document = $newDocument;
        $document['expires'] = CRM_Utils_Time::getTimeRaw() + $document['ttl'];
114
115
      }
      else {
116
        // keep the old messages for now, try again later
117
118
119
120
121
122
123
124
125
126
127
128
129
        $document['expires'] = CRM_Utils_Time::getTimeRaw() + $document['retry'];
      }
      $isChanged = TRUE;
    }

    if ($isChanged) {
      $this->cache->set('communityMessages', $document);
    }

    return $document;
  }

  /**
130
   * Download document from URL and parse as JSON.
131
   *
132
133
   * @return NULL|array
   *   parsed JSON
134
   */
135
136
  public function fetchDocument() {
    list($status, $json) = $this->client->get($this->getRenderedUrl());
137
138
139
140
141
142
143
144
145
146
    if ($status != CRM_Utils_HttpClient::STATUS_OK || empty($json)) {
      return NULL;
    }
    $doc = json_decode($json, TRUE);
    if (empty($doc) || json_last_error() != JSON_ERROR_NONE) {
      return NULL;
    }
    return $doc;
  }

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  /**
   * Get the final, usable URL string (after interpolating any variables)
   *
   * @return FALSE|string
   */
  public function getRenderedUrl() {
    return CRM_Utils_System::evalUrl($this->messagesUrl);
  }

  /**
   * @return bool
   */
  public function isEnabled() {
    return $this->messagesUrl !== FALSE && $this->messagesUrl !== 'FALSE';
  }

163
  /**
164
   * Pick a message to display.
165
166
167
   *
   * @return NULL|array
   */
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  public function pick() {
    $document = $this->getDocument();
    $messages = array();
    foreach ($document['messages'] as $message) {
      if (!isset($message['perms'])) {
        $message['perms'] = array(self::DEFAULT_PERMISSION);
      }
      if (!CRM_Core_Permission::checkAnyPerm($message['perms'])) {
        continue;
      }

      if (isset($message['components'])) {
        $enabled = array_keys(CRM_Core_Component::getEnabledComponents());
        if (count(array_intersect($enabled, $message['components'])) == 0) {
          continue;
        }
      }

      $messages[] = $message;
    }
    if (empty($messages)) {
      return NULL;
    }

    $idx = rand(0, count($messages) - 1);
    return $messages[$idx];
194
195
196
197
198
199
200
  }

  /**
   * @param string $markup
   * @return string
   */
  public static function evalMarkup($markup) {
201
202
203
204
205
206
207
208
209
210
211
212
213
    $config = CRM_Core_Config::singleton();
    $vals = array(
      'resourceUrl' => rtrim($config->resourceBase, '/'),
      'ver' => CRM_Utils_System::version(),
      'uf' => $config->userFramework,
      'php' => phpversion(),
      'sid' => md5('sid_' . (defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY : '') . '_' . $config->userFrameworkBaseURL),
      'baseUrl' => $config->userFrameworkBaseURL,
      'lang' => $config->lcMessages,
      'co' => $config->defaultContactCountry,
    );
    $vars = array();
    foreach ($vals as $k => $v) {
214
215
      $vars['%%' . $k . '%%'] = $v;
      $vars['{{' . $k . '}}'] = urlencode($v);
216
217
    }
    return strtr($markup, $vars);
218
219
  }

totten's avatar
totten committed
220
221
222
223
224
225
226
  /**
   * Ensure that a document is well-formed
   *
   * @param array $document
   * @return bool
   */
  public function validateDocument($document) {
yashodha's avatar
yashodha committed
227
    if (!isset($document['ttl']) || !is_int($document['ttl'])) {
totten's avatar
totten committed
228
229
      return FALSE;
    }
yashodha's avatar
yashodha committed
230
    if (!isset($document['retry']) || !is_int($document['retry'])) {
totten's avatar
totten committed
231
232
233
234
235
236
237
238
239
240
241
242
      return FALSE;
    }
    if (!isset($document['messages']) || !is_array($document['messages'])) {
      return FALSE;
    }
    foreach ($document['messages'] as $message) {
      // TODO validate $message['markup']
    }

    return TRUE;
  }

243
}