1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
37:
38: 39: 40: 41:
42: class Events extends X2ActiveRecord {
43:
44: public $photo;
45:
46: 47: 48: 49:
50: public static function model($className = __CLASS__) {
51: return parent::model($className);
52: }
53:
54: 55: 56:
57: public function tableName() {
58: return 'x2_events';
59: }
60:
61: public function attributeNames () {
62: return array_merge (
63: parent::attributeNames (),
64: array (
65: 'photo',
66: )
67: );
68: }
69:
70: public function relations() {
71: $relationships = array();
72: $relationships = array_merge($relationships, array(
73: 'children' => array(
74: self::HAS_MANY, 'Events', 'associationId',
75: 'condition' => 'children.associationType="Events"'),
76: 'profile' => array(self::HAS_ONE, 'Profile',
77: array ('username' => 'user')),
78: 'userObj' => array(self::HAS_ONE, 'User',
79: array ('username' => 'user')),
80: 'media' => array (
81: self::MANY_MANY, 'Media', 'x2_events_to_media(eventsId, mediaId)'),
82:
83: 'legacyMedia' => array (
84: self::HAS_ONE, 'Media', array ('id' => 'associationId')),
85: ));
86: return $relationships;
87: }
88:
89: public function scopes () {
90: return array (
91: 'comments' => array (
92: 'condition' => 'associationType="Events" and associationId=:id',
93: 'params' => array (':id' => $this->id)
94: )
95: );
96: }
97:
98: 99: 100:
101: public function rules() {
102:
103:
104: return array(
105: );
106: }
107:
108: public function save ($runValidation=true, $attributes=null) {
109: if ($this->photo) {
110:
111:
112: $transaction = Yii::app()->db->beginTransaction ();
113: try {
114:
115: $ret = parent::save ($runValidation, $attributes);
116: if (!$ret) {
117: throw new CException (implode (';', $this->getAllErrorMessages ()));
118: }
119:
120:
121: $media = new Media;
122: $media->setAttributes (array (
123: 'fileName' => $this->photo->getName (),
124: 'mimetype' => $this->photo->type,
125: ), false);
126: $media->resolveNameConflicts ();
127: if (!$media->save ()) {
128: throw new CException (implode (';', $media->getAllErrorMessages ()));
129: }
130:
131:
132: $tempName = $this->photo->getTempName ();
133: $username = Yii::app()->user->getName ();
134: if (!FileUtil::ccopy(
135: $tempName,
136: "uploads/protected/media/$username/{$media->fileName}")) {
137:
138: throw new CException ();
139: }
140:
141:
142: $join = new RelationshipsJoin ('insert', 'x2_events_to_media');
143: $join->eventsId = $this->id;
144: $join->mediaId = $media->id;
145: if (!$join->save ()) {
146: throw new CException (implode (';', $join->getAllErrorMessages ()));
147: }
148:
149: $transaction->commit ();
150: return $ret;
151: } catch (CException $e) {
152: $transaction->rollback ();
153: return false;
154: }
155: } else {
156: return parent::save ($runValidation, $attributes);
157: }
158: }
159:
160: public function renderFrameLink ($htmlOptions) {
161: if (Yii::app()->params->isMobileApp &&
162: !X2LinkableBehavior::isMobileLinkableRecordType ($this->associationType)) {
163:
164: return Events::parseModelName ($this->associationType);
165: }
166: return CHtml::link(
167: Events::parseModelName($this->associationType),
168: '#', array_merge($htmlOptions, array(
169: 'class' => 'action-frame-link',
170: 'data-action-id' => $this->associationId
171: ))
172: );
173: }
174:
175: public function getRecipient () {
176: $recipUser = Yii::app()->db->createCommand()
177: ->select('username')
178: ->from('x2_users')
179: ->where('id=:id', array(':id' => $this->associationId))
180: ->queryScalar();
181: $recipient = '';
182: if ($this->user != $recipUser && $this->associationId != 0) {
183: if (Yii::app()->user->getId() == $this->associationId) {
184: $recipient =
185: CHtml::link(
186: Yii::t('app', 'You'),
187: Yii::app()->params->profile->getUrl ());
188: } else {
189: $recipient = User::getUserLinks($recipUser);
190: }
191: }
192: return $recipient;
193: }
194:
195: 196: 197: 198: 199:
200: public static function parseModelName($model) {
201:
202:
203:
204: $customModule = Modules::model()->findByAttributes(array(
205: 'custom' => 1,
206: 'name' => $model,
207: 'moduleType'=>'module',
208: ));
209: if ($customModule) {
210:
211: $model = Modules::itemDisplayName($customModule->name);
212: $model = strtolower($model);
213: } else {
214: switch ($model) {
215: case 'Product':
216: $model .= 's'; break;
217: case 'Quote':
218: $model .= 's'; break;
219: case 'Opportunity':
220: $model = str_replace('y', 'ies', $model); break;
221: }
222: $requestedModel = $model;
223: $model = Modules::displayName(false, ucfirst($model));
224: $model = strtolower($model);
225: if (empty($model)) {
226:
227:
228: if ($requestedModel === 'AnonContact')
229: $model = 'anonymous contact';
230: else if ($requestedModel === 'Campaign')
231: $model = 'campaign';
232: }
233: }
234: return Yii::t('app', $model);
235: }
236:
237: public function getText(array $params = array(), array $htmlOptions = array()) {
238: $truncated = (array_key_exists('truncated', $params)) ? $params['truncated'] : false;
239: $requireAbsoluteUrl = (array_key_exists('requireAbsoluteUrl', $params)) ? $params['requireAbsoluteUrl'] : false;
240: $text = "";
241: $authorText = "";
242: if (Yii::app()->user->getName() == $this->user) {
243: $authorText = CHtml::link(
244: Yii::t('app', 'You'), $this->profile->url, $htmlOptions);
245: } else {
246: $authorText = User::getUserLinks($this->user);
247: }
248: if (!empty($authorText)) {
249: $authorText.=" ";
250: }
251: switch ($this->type) {
252: case 'notif':
253: $parent = X2Model::model('Notification')->findByPk($this->associationId);
254: if (isset($parent)) {
255: $text = $parent->getMessage();
256: } else {
257: $text = Yii::t('app', "Notification not found");
258: }
259: break;
260: case 'record_create':
261: $actionFlag = false;
262: if (class_exists($this->associationType)) {
263: if (count(X2Model::model($this->associationType)
264: ->findAllByPk($this->associationId)) > 0) {
265:
266: if ($this->associationType == 'Actions') {
267: $action = X2Model::model('Actions')->findByPk($this->associationId);
268: if (isset($action) &&
269: (strcasecmp($action->associationType, 'contacts') === 0 ||
270: in_array($action->type, array('call', 'note', 'time')))) {
271:
272:
273: $actionFlag = true;
274:
275: $relatedAction = Actions::model()->findByPk ($this->associationId);
276: if ($relatedAction){
277: $authorText = User::getUserLinks ($relatedAction->assignedTo);
278: }
279: }
280: }
281: if ($actionFlag) {
282: $authorText = empty($authorText) ?
283: Yii::t('app', 'Someone') : $authorText;
284: switch ($action->type) {
285: case 'call':
286: $text = Yii::t('app', '{authorText} logged a call ({duration}) with {modelLink}.', array(
287: '{authorText}' => $authorText,
288: '{duration}' => empty($action->dueDate) || empty($action->completeDate) ? Yii::t('app', 'duration unknown') : Formatter::formatTimeInterval($action->dueDate, $action->completeDate, '{hoursMinutes}'),
289: '{modelLink}' => X2Model::getModelLink($action->associationId, ucfirst($action->associationType), $requireAbsoluteUrl)
290: ));
291: break;
292: case 'note':
293: $text = Yii::t('app', '{authorText} posted a comment on {modelLink}.', array(
294: '{authorText}' => $authorText,
295: '{modelLink}' => X2Model::getModelLink($action->associationId, ucfirst($action->associationType), $requireAbsoluteUrl)
296: ));
297: break;
298: case 'time':
299: $text = Yii::t('app', '{authorText} logged {time} on {modelLink}.', array(
300: '{authorText}' => $authorText,
301: '{time}' => Formatter::formatTimeInterval($action->dueDate, $action->dueDate + $action->timeSpent, '{hoursMinutes}'),
302: '{modelLink}' => X2Model::getModelLink($action->associationId, ucfirst($action->associationType))
303: ));
304: break;
305: default:
306: if (!empty($authorText)
307: && $authorText != Yii::t('app', 'Anyone')
308: && $authorText != Yii::t('app', 'Someone')) {
309: $text = Yii::t(
310: 'app',
311: "A new {actionLink} associated with the contact ".
312: "{contactLink} has been assigned to {authorText}",
313: array(
314: '{authorText}' => $authorText,
315: '{actionLink}' => $this->renderFrameLink (
316: $htmlOptions),
317: '{contactLink}' => X2Model::getModelLink(
318: $action->associationId,
319: ucfirst($action->associationType),
320: $requireAbsoluteUrl
321: )
322: )
323: );
324: } else {
325: $text = Yii::t(
326: 'app',
327: "A new {actionLink} associated with the contact ".
328: "{contactLink} has been created.",
329: array(
330: '{actionLink}' => $this->renderFrameLink (
331: $htmlOptions),
332: '{contactLink}' => X2Model::getModelLink(
333: $action->associationId,
334: ucfirst($action->associationType),
335: $requireAbsoluteUrl
336: )
337: )
338: );
339: }
340: }
341: } else {
342: if (!empty($authorText)) {
343: $modelLink = X2Model::getModelLink (
344: $this->associationId, $this->associationType, $requireAbsoluteUrl);
345: if (isset($action) && $this->user !== $action->assignedTo) {
346:
347: $translateText = "created a new {modelName} for {assignee}, {modelLink}";
348: } elseif (
349:
350: $modelLink !== '') {
351:
352: $translateText = "created a new {modelName}, {modelLink}";
353: } else {
354: $translateText = "created a new {modelName}";
355: }
356: $text = $authorText . Yii::t('app', $translateText, array(
357: '{modelName}' => Events::parseModelName($this->associationType),
358: '{modelLink}' => $modelLink,
359: '{assignee}' => isset($action) ? User::getUserLinks ($action->assignedTo) : null,
360: ));
361: } else {
362: $text = Yii::t('app', "A new {modelName}, {modelLink}, has been created.", array('{modelName}' => Events::parseModelName($this->associationType),
363: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType, $requireAbsoluteUrl)));
364: }
365: }
366: } else {
367: $deletionEvent = X2Model::model('Events')->findByAttributes(array('type' => 'record_deleted', 'associationType' => $this->associationType, 'associationId' => $this->associationId));
368: if (isset($deletionEvent)) {
369: if (!empty($authorText)) {
370: $text = $authorText . Yii::t('app', "created a new {modelName}, {deletionText}. It has been deleted.", array(
371: '{modelName}' => Events::parseModelName($this->associationType),
372: '{deletionText}' => $deletionEvent->text,
373: ));
374: } else {
375: $text = Yii::t('app', "A {modelName}, {deletionText}, was created. It has been deleted.", array(
376: '{modelName}' => Events::parseModelName($this->associationType),
377: '{deletionText}' => $deletionEvent->text,
378: ));
379: }
380: } else {
381: if (!empty($authorText)) {
382: $text = $authorText . Yii::t('app', "created a new {modelName}, but it could not be found.", array(
383: '{modelName}' => Events::parseModelName($this->associationType)
384: ));
385: } else {
386: $text = Yii::t('app', "A {modelName} was created, but it could not be found.", array(
387: '{modelName}' => Events::parseModelName($this->associationType)
388: ));
389: }
390: }
391: }
392: }
393: break;
394: case 'weblead_create':
395: if (count(X2Model::model($this->associationType)->findAllByPk($this->associationId)) > 0) {
396: $text = Yii::t('app', "A new web lead has come in: {modelLink}", array(
397: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType)
398: ));
399: } else {
400: $deletionEvent = X2Model::model('Events')->findByAttributes(array('type' => 'record_deleted', 'associationType' => $this->associationType, 'associationId' => $this->associationId));
401: if (isset($deletionEvent)) {
402: $text = Yii::t('app', "A new web lead has come in: {deletionText}. It has been deleted.", array(
403: '{deletionText}' => $deletionEvent->text
404: ));
405: } else {
406: $text = Yii::t('app', "A new web lead has come in, but it could not be found.");
407: }
408: }
409: break;
410: case 'record_deleted':
411: if (class_exists($this->associationType)) {
412: if (((Yii::app()->params->profile !== null && Yii::app()->params->profile->language != 'en' && !empty(Yii::app()->params->profile->language)) ||
413: (Yii::app()->params->profile === null && Yii::app()->language !== 'en')) ||
414: (strpos($this->associationType, 'A') !== 0 && strpos($this->associationType, 'E') !== 0 && strpos($this->associationType, 'I') !== 0 &&
415: strpos($this->associationType, 'O') !== 0 && strpos($this->associationType, 'U') !== 0)) {
416: if (!empty($authorText)) {
417: $text = $authorText . Yii::t('app', "deleted a {modelType}, {text}", array(
418: '{modelType}' => Events::parseModelName($this->associationType),
419: '{text}' => $this->text
420: ));
421: } else {
422: $text = Yii::t('app', "A {modelType}, {text}, was deleted", array(
423: '{modelType}' => Events::parseModelName($this->associationType),
424: '{text}' => $this->text
425: ));
426: }
427: } else {
428: if (!empty($authorText)) {
429: $text = $authorText . Yii::t('app', "deleted an {modelType}, {text}.", array(
430: '{modelType}' => Events::parseModelName($this->associationType),
431: '{text}' => $this->text
432: ));
433: } else {
434: $text = Yii::t('app', "An {modelType}, {text}, was deleted.", array(
435: '{modelType}' => Events::parseModelName($this->associationType),
436: '{text}' => $this->text
437: ));
438: }
439: }
440: }
441: break;
442: case 'workflow_start':
443: $action = X2Model::model('Actions')->findByPk($this->associationId);
444: if (isset($action)) {
445: $record = X2Model::model(ucfirst($action->associationType))->findByPk($action->associationId);
446: if (isset($record)) {
447: if (isset($action->workflowStage)) {
448: $text = $authorText . Yii::t('app', 'started the process stage "{stage}" for the {modelName} {modelLink}', array(
449: '{stage}' => $action->workflowStage->name,
450: '{modelName}' => Events::parseModelName($action->associationType),
451: '{modelLink}' => X2Model::getModelLink($action->associationId, $action->associationType)
452: ));
453: } else {
454: $text = $authorText . Yii::t('app', "started a process stage for the {modelName} {modelLink}, but the process stage could not be found.", array(
455: '{modelName}' => Events::parseModelName($action->associationType),
456: '{modelLink}' => X2Model::getModelLink($action->associationId, $action->associationType)
457: ));
458: }
459: } else {
460: $text = $authorText . Yii::t('app', "started a process stage, but the associated {modelName} was not found.", array(
461: '{modelName}' => Events::parseModelName($action->associationType)
462: ));
463: }
464: } else {
465: $text = $authorText . Yii::t('app', "started a process stage, but the process record could not be found.");
466: }
467: break;
468: case 'workflow_complete':
469: $action = X2Model::model('Actions')->findByPk($this->associationId);
470: if (isset($action)) {
471: $record = X2Model::model(ucfirst($action->associationType))->findByPk($action->associationId);
472: if (isset($record)) {
473: if (isset($action->workflowStage)) {
474: $text = $authorText . Yii::t('app', 'completed the process stage "{stageName}" for the {modelName} {modelLink}', array(
475: '{stageName}' => $action->workflowStage->name,
476: '{modelName}' => Events::parseModelName($action->associationType),
477: '{modelLink}' => X2Model::getModelLink($action->associationId, $action->associationType)
478: ));
479: } else {
480: $text = $authorText . Yii::t('app', "completed a process stage for the {modelName} {modelLink}, but the process stage could not be found.", array(
481: '{modelName}' => Events::parseModelName($action->associationType),
482: '{modelLink}' => X2Model::getModelLink($action->associationId, $action->associationType)
483: ));
484: }
485: } else {
486: $text = $authorText . Yii::t('app', "completed a process stage, but the associated {modelName} was not found.", array(
487: '{modelName}' => Events::parseModelName($action->associationType)
488: ));
489: }
490: } else {
491: $text = $authorText . Yii::t('app', "completed a process stage, but the process record could not be found.");
492: }
493: break;
494: case 'workflow_revert':
495: $action = X2Model::model('Actions')->findByPk($this->associationId);
496: if (isset($action)) {
497: $record = X2Model::model(ucfirst($action->associationType))->findByPk($action->associationId);
498: if (isset($record)) {
499: if (isset($action->workflowStage)) {
500: $text = $authorText . Yii::t('app', 'reverted the process stage "{stageName}" for the {modelName} {modelLink}', array(
501: '{stageName}' => $action->workflowStage->name,
502: '{modelName}' => Events::parseModelName($action->associationType),
503: '{modelLink}' => X2Model::getModelLink($action->associationId, $action->associationType)
504: ));
505: } else {
506: $text = $authorText . Yii::t('app', "reverted a process stage for the {modelName} {modelLink}, but the process stage could not be found.", array(
507: '{modelName}' => Events::parseModelName($action->associationType),
508: '{modelLink}' => X2Model::getModelLink($action->associationId, $action->associationType)
509: ));
510: }
511: } else {
512: $text = $authorText . Yii::t('app', "reverted a process stage, but the associated {modelName} was not found.", array(
513: '{modelName}' => Events::parseModelName($action->associationType)
514: ));
515: }
516: } else {
517: $text = $authorText . Yii::t('app', "reverted a process stage, but the process record could not be found.");
518: }
519: break;
520: case 'structured-feed':
521: case 'feed':
522: if (Yii::app()->user->getName() == $this->user) {
523: $author = CHtml::link(Yii::t('app', 'You'), Yii::app()->controller->createAbsoluteUrl('/profile/view', array('id' => Yii::app()->user->getId())), $htmlOptions) . " ";
524: } else {
525:
526: $author = User::getUserLinks($this->user);
527: }
528: $modifier = '';
529: $recipient = $this->getRecipient ();
530: if ($recipient) {
531: $modifier = ' » ';
532: }
533: $text = $author . $modifier . $recipient . ": " . ($truncated ? strip_tags(Formatter::convertLineBreaks(x2base::convertUrls($this->text), true, true), '<a></a>') : $this->text);
534: break;
535: case 'email_sent':
536: if (class_exists($this->associationType)) {
537: $model = X2Model::model($this->associationType)->findByPk($this->associationId);
538: if (!empty($model)) {
539: switch ($this->subtype) {
540: case 'quote':
541: $text = $authorText . Yii::t('app', "issued the {transModelName} \"{modelLink}\" via email", array(
542: '{transModelName}' => Yii::t('quotes', 'quote'),
543: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType)
544: ));
545: break;
546: case 'invoice':
547: $text = $authorText . Yii::t('app', "issued the {transModelName} \"{modelLink}\" via email", array(
548: '{transModelName}' => Yii::t('quotes', 'invoice'),
549: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType)
550: ));
551: break;
552: default:
553: $text = $authorText . Yii::t('app', "sent an email to the {transModelName} {modelLink}", array(
554: '{transModelName}' => Events::parseModelName($this->associationType),
555: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType)
556: ));
557: break;
558: }
559: } else {
560: $deletionEvent = X2Model::model('Events')->findByAttributes(array('type' => 'record_deleted', 'associationType' => $this->associationType, 'associationId' => $this->associationId));
561: switch ($this->subtype) {
562: case 'quote':
563: if (isset($deletionEvent)) {
564: $text = $authorText . Yii::t('app', "issued a quote by email, but that record has been deleted.");
565: } else {
566: $text = $authorText . Yii::t('app', "issued a quote by email, but that record could not be found.");
567: }
568: break;
569: case 'invoice':
570: if (isset($deletionEvent)) {
571: $text = $authorText . Yii::t('app', "issued an invoice by email, but that record has been deleted.");
572: } else {
573: $text = $authorText . Yii::t('app', "issued an invoice by email, but that record could not be found.");
574: }
575: break;
576: default:
577: if (isset($deletionEvent)) {
578: $text = $authorText . Yii::t('app', "sent an email to a {transModelName}, but that record has been deleted.", array(
579: '{transModelName}' => Events::parseModelName($this->associationType)
580: ));
581: } else {
582: $text = $authorText . Yii::t('app', "sent an email to a {transModelName}, but that record could not be found.", array(
583: '{transModelName}' => Events::parseModelName($this->associationType)
584: ));
585: }
586: break;
587: }
588: }
589: }
590: break;
591: case 'email_opened':
592: switch ($this->subtype) {
593: case 'quote':
594: $emailType = Yii::t('app', 'a quote email');
595: break;
596: case 'invoice':
597: $emailType = Yii::t('app', 'an invoice email');
598: break;
599: default:
600: $emailType = Yii::t('app', 'an email');
601: break;
602: }
603: if (X2Model::getModelName($this->associationType) && count(X2Model::model($this->associationType)->findAllByPk($this->associationId)) > 0) {
604: $text = X2Model::getModelLink($this->associationId, $this->associationType) . Yii::t('app', ' has opened {emailType}!', array(
605: '{emailType}' => $emailType,
606: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType)
607: ));
608: } else {
609: $text = Yii::t('app', "A contact has opened {emailType}, but that contact cannot be found.", array('{emailType}' => $emailType));
610: }
611: break;
612: case 'email_clicked':
613: if (count(X2Model::model($this->associationType)->findAllByPk($this->associationId)) > 0) {
614: $text = X2Model::getModelLink($this->associationId, $this->associationType) . Yii::t('app', ' opened a link in an email campaign and is visiting your website!', array(
615: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType)
616: ));
617: } else {
618: $text = Yii::t('app', "A contact has opened a link in an email campaign, but that contact cannot be found.");
619: }
620: break;
621: case 'web_activity':
622: if (count(X2Model::model($this->associationType)->findAllByPk($this->associationId)) > 0) {
623: $text = "";
624:
625: $text .= X2Model::getModelLink($this->associationId, $this->associationType) . " " . Yii::t('app', "is currently on your website!");
626: }else {
627: $text = Yii::t('app', "A contact was on your website, but that contact cannot be found.");
628: }
629: break;
630: case 'case_escalated':
631: if (count(X2Model::model($this->associationType)->findAllByPk($this->associationId)) > 0) {
632: $case = X2Model::model($this->associationType)->findByPk($this->associationId);
633: $text = $authorText . Yii::t('app', "escalated service case {modelLink} to {userLink}", array(
634: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType),
635: '{userLink}' => User::getUserLinks($case->escalatedTo)
636: ));
637: } else {
638: $text = $authorText . Yii::t('app', "escalated a service case but that case could not be found.");
639: }
640: break;
641: case 'calendar_event':
642: $action = X2Model::model('Actions')->findByPk($this->associationId);
643: if (!Yii::app()->params->isMobileApp ||
644: X2LinkableBehavior::isMobileLinkableRecordType ('Calendar')) {
645:
646: $calendarText = CHtml::link(
647: Yii::t('calendar', 'Calendar'),
648: Yii::app()->controller->createAbsoluteUrl(
649: '/calendar/calendar/index'), $htmlOptions);
650: } else {
651: $calendarText = Yii::t('calendar', 'Calendar');
652: }
653: if (isset($action)) {
654: $text = Yii::t('app', "{calendarText} event: {actionDescription}", array(
655: '{calendarText}' => $calendarText,
656: '{actionDescription}' => CHtml::encode($action->actionDescription)
657: ));
658: } else {
659: $text = Yii::t('app', "{calendarText} event: event not found.", array(
660: '{calendarText}' => $calendarText
661: ));
662: }
663: break;
664: case 'action_reminder':
665: $action = X2Model::model('Actions')->findByPk($this->associationId);
666: if (isset($action)) {
667: $text = Yii::t('app', "Reminder! The following {action} is due now: {transModelLink}", array(
668: '{transModelLink}' => X2Model::getModelLink($this->associationId, $this->associationType),
669: '{action}' => strtolower(Modules::displayName (false, 'Actions')),
670: ));
671: } else {
672: $text = Yii::t('app', "An {action} is due now, but the record could not be found.", array(
673: '{action}' => strtolower(Modules::displayName (false, 'Actions')),
674: ));
675: }
676: break;
677: case 'action_complete':
678: $action = X2Model::model('Actions')->findByPk($this->associationId);
679: if (isset($action)) {
680: $text = $authorText . Yii::t('app', "completed the following {action}: {actionDescription}", array(
681: '{actionDescription}' => X2Model::getModelLink(
682: $this->associationId, $this->associationType, $requireAbsoluteUrl),
683: '{action}' => strtolower(Modules::displayName (false, 'Actions')),
684: )
685: );
686: } else {
687: $text = $authorText . Yii::t('app', "completed an {action}, but the record could not be found.", array(
688: '{action}' => strtolower(Modules::displayName (false, 'Actions')),
689: ));
690: }
691: break;
692: case 'doc_update':
693: $text = $authorText . Yii::t('app', 'updated a document, {docLink}', array(
694: '{docLink}' => X2Model::getModelLink($this->associationId, $this->associationType)
695: ));
696: break;
697: case 'email_from':
698: if (class_exists($this->associationType)) {
699: if (count(X2Model::model($this->associationType)->findAllByPk($this->associationId)) > 0) {
700: $email = Yii::t('app', 'email');
701: if ($this->associationType === 'Actions' && $this->subtype = 'email') {
702: $action = X2Model::model('Actions')->findByPk ($this->associationId);
703: if ($action) {
704: $multiAssociations = $action->getMultiassociations();
705: if (isset($multiAssociations['Contacts'])) {
706:
707: $contact = $multiAssociations['Contacts'][0];
708: $modelName = Events::parseModelName('Contacts');
709: $emailLink = X2Model::getModelLink($action->id, 'Actions');
710: $modelLink = X2Model::getModelLink($contact->id, 'Contacts');
711: $email = Yii::t('app', 'email') . ' '. $emailLink;
712: }
713: }
714: } else {
715: $modelName = Events::parseModelName($this->associationType);
716: $modelLink = X2Model::getModelLink($this->associationId, $this->associationType);
717: }
718: $text = $authorText . Yii::t('app', "received an {email} from a {transModelName}, {modelLink}", array(
719: '{email}' => $email,
720: '{transModelName}' => $modelName,
721: '{modelLink}' => $modelLink,
722: ));
723: } else {
724: $deletionEvent = X2Model::model('Events')->findByAttributes(array('type' => 'record_deleted', 'associationType' => $this->associationType, 'associationId' => $this->associationId));
725: if (isset($deletionEvent)) {
726: $text = $authorText . Yii::t('app', "received an email from a {transModelName}, but that record has been deleted.", array(
727: '{transModelName}' => Events::parseModelName($this->associationType)
728: ));
729: } else {
730: $text = $authorText . Yii::t('app', "received an email from a {transModelName}, but that record could not be found.", array(
731: '{transModelName}' => Events::parseModelName($this->associationType)
732: ));
733: }
734: }
735: }
736:
737: break;
738: case 'voip_call':
739: if (count(X2Model::model($this->associationType)->findAllByPk($this->associationId)) > 0) {
740: $text = Yii::t('app', "{modelLink} called.", array(
741: '{modelLink}' => X2Model::getModelLink($this->associationId, $this->associationType)
742: ));
743: } else {
744: $deletionEvent = X2Model::model('Events')->findByAttributes(array('type' => 'record_deleted', 'associationType' => $this->associationType, 'associationId' => $this->associationId));
745: if (isset($deletionEvent)) {
746: $text = $authorText . Yii::t('app', "A contact called, but the contact record has been deleted.");
747: } else {
748: $text = $authorText . Yii::t('app', "Call from a contact whose record could not be found.");
749: }
750: }
751:
752: break;
753: case 'media':
754: $media = $this->legacyMedia;
755: $text = substr($authorText, 0, -1) . ": " . $this->text;
756: if (isset($media)) {
757: if (!$truncated) {
758: $text.="<br>" . Media::attachmentSocialText($media->getMediaLink(), true, true);
759: } else {
760: $text.="<br>" . Media::attachmentSocialText($media->getMediaLink(), true, false);
761: }
762: } else {
763: $text.="<br>Media file not found.";
764: }
765: break;
766: case 'topic_reply':
767: $reply = TopicReplies::model()->findByPk($this->associationId);
768: if (isset($reply)) {
769: if (!Yii::app()->params->isMobileApp) {
770: $topicLink = X2Html::link(
771: $reply->topic->name,
772: Yii::app()->controller->createUrl(
773: '/topics/topics/view',
774: array('id' => $reply->topic->id, 'replyId' => $reply->id)));
775: } else {
776: $topicLink = $reply->topic->name;
777: }
778: $text = Yii::t('topics', '{poster} posted a new reply to {topic}.', array(
779: '{poster}' => $authorText,
780: '{topic}' => $topicLink,
781: ));
782:
783:
784:
785:
786:
787:
788: } else {
789: $text = Yii::t('topics', '{poster} posted a new reply to a topic, but that reply has been deleted.', array(
790: '{poster}' => $authorText,
791: ));
792: }
793: break;
794: default:
795: $text = $authorText . CHtml::encode($this->text);
796: break;
797: }
798: if ($truncated && mb_strlen($text, 'UTF-8') > 250) {
799: $text = mb_substr($text, 0, 250, 'UTF-8') . "...";
800: }
801: return $text;
802: }
803:
804: public static $eventLabels = array(
805: 'feed' => 'Social Posts',
806: 'comment' => 'Comment',
807: 'record_create' => 'Records Created',
808: 'record_deleted' => 'Records Deleted',
809: 'action_reminder' => 'Action Reminders',
810: 'action_complete' => 'Actions Completed',
811: 'calendar_event' => 'Calendar Events',
812: 'case_escalated' => 'Cases Escalated',
813: 'email_opened' => 'Emails Opened',
814: 'email_sent' => 'Emails Sent',
815: 'notif' => 'Notifications',
816: 'weblead_create' => 'Webleads Created',
817: 'web_activity' => 'Web Activity',
818: 'workflow_complete' => 'Process Complete',
819: 'workflow_revert' => 'Process Reverted',
820: 'workflow_start' => 'Process Started',
821: 'doc_update' => 'Doc Updates',
822: 'email_from' => 'Email Received',
823: 'media' => 'Media',
824: 'voip_call' => 'VOIP Call',
825: 'topic_reply' => 'Topic Replies',
826: );
827:
828: public static function parseType($type) {
829: if (array_key_exists($type, self::$eventLabels))
830: $type = self::$eventLabels[$type];
831:
832: return Yii::t('app', $type);
833: }
834:
835: 836: 837:
838: public static function deleteOldEvents() {
839: $dateRange = Yii::app()->settings->eventDeletionTime;
840: if (!empty($dateRange)) {
841: $dateRange = $dateRange * 24 * 60 * 60;
842: $deletionTypes = json_decode(Yii::app()->settings->eventDeletionTypes, true);
843: if (!empty($deletionTypes)) {
844: $deletionTypes = "('" . implode("','", $deletionTypes) . "')";
845: $time = time() - $dateRange;
846: X2Model::model('Events')->deleteAll(
847: 'lastUpdated < ' . $time . ' AND type IN ' . $deletionTypes);
848: }
849: }
850: }
851:
852: 853: 854: 855:
856: public function isVisibleTo ($user) {
857: if (Yii::app()->params->isAdmin) return true;
858: if (!$user) return false;
859:
860: $assignedUser = null;
861: if ($this->associationType === 'User') {
862: $assignedUser = User::model ()->findByPk ($this->associationId);
863: }
864: switch (Yii::app()->settings->historyPrivacy) {
865: case 'group':
866: if (in_array ($this->user, Groups::getGroupmates ($user->id)) ||
867: ($this->associationType === 'User' &&
868: $assignedUser &&
869: in_array ($assignedUser->username, Groups::getGroupmates ($user->id)))) {
870:
871: return true;
872: }
873:
874: case 'user':
875: if ($this->user === $user->username ||
876: ($this->associationType === 'User' &&
877: ($this->associationId === $user->id))) {
878:
879: return true;
880: }
881: break;
882: default:
883: return ($this->user === $user->username || $this->visibility ||
884: $this->associationType === 'User' && $this->associationId === $user->id);
885: }
886: return false;
887: }
888:
889: 890: 891: 892: 893:
894: public function getAccessCriteria (Profile $profile=null) {
895: $criteria = new CDbCriteria;
896:
897:
898: $criteria->addCondition ('TRUE');
899: if (!Yii::app()->params->isAdmin) {
900: $criteria->params[':getAccessCriteria_username'] = Yii::app()->user->getName ();
901: $criteria->params[':getAccessCriteria_userId'] = Yii::app()->user->getId ();
902: $userCondition = '
903: user=:getAccessCriteria_username OR
904: associationType="User" AND associationId=:getAccessCriteria_userId
905: ';
906: if (Yii::app()->settings->historyPrivacy == 'user') {
907: $criteria->addCondition ($userCondition);
908: } elseif (Yii::app()->settings->historyPrivacy == 'group') {
909: $criteria->addCondition ("
910: $userCondition OR
911: user IN (
912: SELECT DISTINCT b.username
913: FROM x2_group_to_user a JOIN x2_group_to_user b
914: ON a.groupId=b.groupId
915: WHERE a.username=:getAccessCriteria_username
916: ) OR (
917: associationType='User' AND associationId in (
918: SELECT DISTINCT b.id
919: FROM x2_group_to_user a JOIN x2_group_to_user b
920: ON a.groupId=b.groupId
921: WHERE a.userId=:getAccessCriteria_userId
922: )
923: )");
924: } else {
925: $criteria->addCondition ("
926: $userCondition OR visibility=1
927: ");
928: }
929: }
930:
931: if ($profile) {
932: $criteria->params[':getAccessCriteria_profileUsername'] = $profile->username;
933: 934:
935: $criteria->addCondition ("user=:getAccessCriteria_profileUsername");
936: if (!Yii::app()->params->isAdmin) {
937: $criteria->addCondition ("visibility=1");
938: }
939: }
940: return $criteria;
941: }
942:
943: 944: 945: 946:
947: private $_permissions;
948: public function checkPermissions ($action=null, $refresh = false) {
949: if (!isset ($this->_permissions) || $refresh) {
950: if (!Yii::app()->params->isAdmin) {
951: $username = Yii::app()->user->getName ();
952: $userId = Yii::app()->user->getId ();
953: $userCondition = '
954: user=:getAccessCriteria_username OR
955: associationType="User" AND associationId=:getAccessCriteria_userId
956: ';
957: $edit = false;
958: $view = $this->user === $username ||
959: strtolower ($this->associationType) === 'user' &&
960: $this->associationId == $userId;
961: if (Yii::app()->settings->historyPrivacy == 'user') {
962: } elseif (Yii::app()->settings->historyPrivacy == 'group') {
963: $view |= in_array (
964: strtolower ($this->user),
965: Yii::app()->db->createCommand ("
966: SELECT LOWER(DISTINCT b.username)
967: FROM x2_group_to_user a JOIN x2_group_to_user b
968: ON a.groupId=b.groupId
969: WHERE a.username=:username
970: ")->queryColumn (array (':username' => $username))) ||
971: $this->associationType==='User' &&
972: in_array (
973: $this->associationId,
974: Yii::app()->db->createCommand ("
975: SELECT DISTINCT b.id
976: FROM x2_group_to_user a JOIN x2_group_to_user b
977: ON a.groupId=b.groupId
978: WHERE a.userId=:userId
979: ")->queryColumn (array (':userId' => $userId)));
980: } else {
981: $view |= $this->visibility;
982: }
983:
984: $edit = $view && $this->type === 'feed' && $this->user === $username;
985: $delete = $view && $this->type === 'feed' &&
986: ($this->user === $username || $this->associationId == $userId);
987: } else {
988: $view = $edit = $delete = true;
989: }
990: $this->_permissions = array (
991: 'view' => $view,
992: 'edit' => $edit,
993: 'delete' => $delete,
994: );
995: } else {
996: extract ($this->_permissions);
997: }
998:
999: if (!$action)
1000: return array('view' => (bool)$view, 'edit' => (bool)$edit, 'delete' => (bool)$delete);
1001: switch ($action) {
1002: case 'view':
1003: return (bool)$view;
1004: case 'edit':
1005: return (bool)$edit;
1006: case 'delete':
1007: return (bool)$delete;
1008: default:
1009: return false;
1010: }
1011: }
1012:
1013: 1014: 1015: 1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023:
1024: public static function getFilteredEventsDataProvider(
1025: $profile, $privateProfile, $filters, $filtersOn) {
1026:
1027: $params = array(':username' => Yii::app()->user->getName ());
1028: $accessCriteria = Events::model ()->getAccessCriteria (!$privateProfile ? $profile : null);
1029:
1030: $visibilityCondition = '';
1031: if ($filtersOn || isset($_SESSION['filters'])) {
1032: if ($filters) {
1033: unset($_SESSION['filters']);
1034: } else {
1035: $filters = $_SESSION['filters'];
1036: $filters = array_map(function ($n) {
1037: return implode(',', $n);
1038: }, $filters);
1039: $filters['default'] = false;
1040: }
1041: $parsedFilters = Events::parseFilters($filters, $params);
1042:
1043: $visibilityFilter = $parsedFilters['filters']['visibility'];
1044: $userFilter = $parsedFilters['filters']['users'];
1045: $typeFilter = $parsedFilters['filters']['types'];
1046: $subtypeFilter = $parsedFilters['filters']['subtypes'];
1047:
1048: $default = $filters['default'];
1049: $_SESSION['filters'] = array(
1050: 'visibility' => $visibilityFilter,
1051: 'users' => $userFilter,
1052: 'types' => $typeFilter,
1053: 'subtypes' => $subtypeFilter
1054: );
1055: if ($default == 'true') {
1056: Yii::app()->params->profile->defaultFeedFilters = json_encode(
1057: $_SESSION['filters']);
1058: Yii::app()->params->profile->save();
1059: }
1060: $visibilityCondition .= $parsedFilters['conditions']['visibility'];
1061: $userCondition = $parsedFilters['conditions']['users'];
1062: $typeCondition = $parsedFilters['conditions']['types'];
1063: $subtypeCondition = $parsedFilters['conditions']['subtypes'];
1064:
1065: $condition = "(associationType is null or associationType!='Events') AND
1066: (type!='action_reminder' " .
1067: "OR user=:username) AND " .
1068: "(type!='notif' OR user=:username)" .
1069: $visibilityCondition . $userCondition . $typeCondition . $subtypeCondition;
1070: $_SESSION['feed-condition'] = $condition;
1071: $_SESSION['feed-condition-params'] = $params;
1072: } else {
1073: $condition = "(associationType is null or associationType!='Events') AND " .
1074: "(type!='action_reminder' OR user=:username) " .
1075: "AND (type!='notif' OR user=:username)" .
1076: $visibilityCondition;
1077: }
1078:
1079: $condition.= " AND timestamp <= " . time();
1080: $condition .= ' AND ('.$accessCriteria->condition.')';
1081:
1082: if (!isset($_SESSION['lastEventId'])) {
1083:
1084: $lastId = Yii::app()->db->createCommand()
1085: ->select('id')
1086: ->from('x2_events')
1087: ->where($condition, array_merge ($params, $accessCriteria->params))
1088: ->order('timestamp DESC, id DESC')
1089: ->limit(1)
1090: ->queryScalar();
1091:
1092: $_SESSION['lastEventId'] = $lastId;
1093: } else {
1094: $lastId = $_SESSION['lastEventId'];
1095: }
1096: $lastTimestamp = Yii::app()->db->createCommand()
1097: ->select('MAX(timestamp)')
1098: ->from('x2_events')
1099: ->where($condition, array_merge ($params, $accessCriteria->params))
1100: ->order('timestamp DESC, id DESC')
1101: ->limit(1)
1102: ->queryScalar();
1103: if (empty($lastTimestamp)) {
1104: $lastTimestamp = 0;
1105: }
1106: if (isset($_SESSION['lastEventId'])) {
1107: $condition.=" AND id <= :lastEventId AND sticky = 0";
1108: $params[':lastEventId'] = $_SESSION['lastEventId'];
1109: }
1110:
1111:
1112: $paginationClass = 'CPagination';
1113:
1114: $dataProvider = new CActiveDataProvider('Events', array(
1115: 'criteria' => array(
1116: 'condition' => $condition,
1117: 'order' => 'timestamp DESC, id DESC',
1118: 'params' => array_merge ($params, $accessCriteria->params),
1119: ),
1120: 'pagination' => array(
1121: 'class' => $paginationClass,
1122: 'pageSize' => 20
1123: ),
1124: ));
1125:
1126: return array(
1127: 'dataProvider' => $dataProvider,
1128: 'lastTimestamp' => $lastTimestamp,
1129: 'lastId' => $lastId
1130: );
1131: }
1132:
1133: private static function parseFilters($filters, &$params) {
1134: unset($filters['filters']);
1135: $visibility = $filters['visibility'];
1136: $visibility = str_replace('Public', '1', $visibility);
1137: $visibility = str_replace('Private', '0', $visibility);
1138: $visibilityFilter = explode(",", $visibility);
1139: if ($visibility != "") {
1140: $visibilityParams = AuxLib::bindArray($visibilityFilter, 'visibility');
1141: $params = array_merge($params, $visibilityParams);
1142: $visibilityCondition = " AND visibility NOT IN (" .
1143: implode(',', array_keys($visibilityParams)) . ")";
1144: } else {
1145: $visibilityCondition = "";
1146: $visibilityFilter = array();
1147: }
1148:
1149: $users = $filters['users'];
1150: if ($users != "") {
1151: $users = explode(",", $users);
1152: $users[] = '';
1153: $users[] = 'api';
1154: $userFilter = $users;
1155: if (sizeof($users)) {
1156: $usersParams = AuxLib::bindArray($users, 'users');
1157: $params = array_merge($params, $usersParams);
1158: $userCondition = " AND (user NOT IN (" .
1159: implode(',', array_keys($usersParams)) . ")";
1160: } else {
1161: $userCondition = "(";
1162: }
1163: if (!in_array('Anyone', $users)) {
1164: $userCondition.=" OR user IS NULL)";
1165: } else {
1166: $userCondition.=")";
1167: }
1168: } else {
1169: $userCondition = "";
1170: $userFilter = array();
1171: }
1172:
1173: $types = $filters['types'];
1174: if ($types != "") {
1175: $types = explode(",", $types);
1176: $typeFilter = $types;
1177: $typesParams = AuxLib::bindArray($types, 'types');
1178: $params = array_merge($params, $typesParams);
1179: $typeCondition = " AND (type NOT IN (" .
1180: implode(',', array_keys($typesParams)) . ") OR important=1)";
1181: } else {
1182: $typeCondition = "";
1183: $typeFilter = array();
1184: }
1185: $subtypes = $filters['subtypes'];
1186: if (is_array($types) && $subtypes != "") {
1187: $subtypes = explode(",", $subtypes);
1188: $subtypeFilter = $subtypes;
1189: if (sizeof($subtypes)) {
1190: $subtypeParams = AuxLib::bindArray($subtypes, 'subtypes');
1191: $params = array_merge($params, $subtypeParams);
1192: $subtypeCondition = " AND (
1193: type!='feed' OR subtype NOT IN (" .
1194: implode(',', array_keys($subtypeParams)) . ") OR important=1)";
1195: } else {
1196: $subtypeCondition = "";
1197: }
1198: } else {
1199: $subtypeCondition = "";
1200: $subtypeFilter = array();
1201: }
1202: $ret = array(
1203: 'filters' => array(
1204: 'visibility' => $visibilityFilter,
1205: 'users' => $userFilter,
1206: 'types' => $typeFilter,
1207: 'subtypes' => $subtypeFilter,
1208: ),
1209: 'conditions' => array(
1210: 'visibility' => $visibilityCondition,
1211: 'users' => $userCondition,
1212: 'types' => $typeCondition,
1213: 'subtypes' => $subtypeCondition,
1214: ),
1215: 'params' => $params,
1216: );
1217: return $ret;
1218: }
1219:
1220: 1221: 1222: 1223: 1224: 1225: 1226: 1227:
1228: public static function getEvents(
1229: $lastEventId, $lastTimestamp, $limit = null, $profile = null, $privateProfile = true) {
1230:
1231: $user = Yii::app()->user->getName();
1232: $criteria = new CDbCriteria();
1233: $prefix = ':getEvents';
1234: $sqlParams = array(
1235: $prefix . 'username' => $user,
1236: $prefix . 'maxTimestamp' => time(),
1237: );
1238: $parameters = array('order' => 'timestamp DESC, id DESC');
1239: if (!is_null($limit) && is_numeric($limit)) {
1240: $parameters['limit'] = $limit;
1241: }
1242:
1243: $sqlParams[$prefix . 'id'] = $lastEventId;
1244: $sqlParams[$prefix . 'timestamp'] = $lastTimestamp;
1245: $accessCriteria = Events::model ()->getAccessCriteria (!$privateProfile ? $profile : null);
1246: if (isset($_SESSION['feed-condition']) && isset($_SESSION['feed-condition-params'])) {
1247: $sqlParams = array_merge($sqlParams, $_SESSION['feed-condition-params']);
1248: $condition = $_SESSION['feed-condition'] . " AND
1249: (`type`!='action_reminder' OR `user`=" . $prefix . "username) AND
1250: (`type`!='notif' OR `user`=" . $prefix . "username) AND
1251: (id > " . $prefix . "id AND (timestamp > " . $prefix . "timestamp AND timestamp < " . $prefix . "maxTimestamp))";
1252: } else {
1253: $condition = '(id > ' . $prefix . 'id AND (timestamp > ' . $prefix . 'timestamp AND timestamp < ' . $prefix . 'maxTimestamp)) AND
1254: (`associationType` is null or `associationType`!="Events")' . " AND
1255: (`type`!='action_reminder' OR `user`=" . $prefix . "username) AND
1256: (`type`!='notif' OR `user`=" . $prefix . "username)";
1257: }
1258:
1259: $sqlParams = array_merge($sqlParams, $accessCriteria->params);
1260: $condition .= " AND ($accessCriteria->condition)";
1261:
1262: $parameters['condition'] = $condition;
1263: $parameters['params'] = $sqlParams;
1264: $criteria->scopes = array('findAll' => array($parameters));
1265:
1266: return array(
1267: 'events' => X2Model::model('Events')->findAll($criteria),
1268: );
1269: }
1270:
1271: public static function generateFeedEmail($filters, $userId, $range, $limit, $eventId, $deleteKey) {
1272: $image = Yii::app()->getAbsoluteBaseUrl(true).'/images/x2engine.png';
1273:
1274: $msg = "<div id='wrap' style='width:6.5in;height:9in;margin-top:auto;margin-left:auto;margin-bottom:auto;margin-right:auto;'><html><body><center>";
1275: $msg .= '<table border="0" cellpadding="0" cellspacing="0" height="100%" id="top-activity" style="background: white; font-family: \'Helvetica Neue\', \'Helvetica\', Helvetica, Arial, sans-serif; font-weight: normal; font-style: normal; font-size: 14px; line-height: 1; color: #222222; position: relative; -webkit-font-smoothing: antialiased;background-color:#FAFAFA;height:25% !important; margin:0; padding:0; width:100% !important;" width="100%">'
1276: . "<tbody><tr><td align=\"center\" style=\"padding-top:20px;\" valign=\"top\">"
1277: . '<table border="0" cellpadding="0" cellspacing="0" id="templateContainer" style="border: 1px solid #DDDDDD;background-color:#FFFFFF;" width="600"><tbody>';
1278: $msg .= '<tr>
1279: <td align="center" valign="top"><!-- // Begin Template Header \\ -->
1280: <table border="0" cellpadding="0" cellspacing="0" id="templateHeader" width="600">
1281: <tbody>
1282: <tr>
1283: <td class="headerContent" style="color:#202020;font-weight:bold;line-height:100%;padding:0;text-align:center;vertical-align:middle;font-family: inherit;font-weight: normal;font-size: 14px;margin-bottom: 17px"><img id="headerImage campaign-icon" src="' . $image .'" style="border:0; height:auto; line-height:100%; outline:none; text-decoration:none;max-width:600px;" /></td>
1284: </tr>
1285: <tr>
1286: <td style="color:#202020;font-weight:bold;padding:5px;text-align:center;vertical-align:middle;font-family: inherit;font-weight: normal;font-size: 14px;"><h2>' . Yii::t('profile', 'Activity Feed Report') . '</h2></td>
1287: </tr>
1288: </tbody>
1289: </table>
1290: <hr width="60%"></td><!-- // End Template Header \\ -->
1291: </tr>';
1292:
1293: $msg.='<tr><td align="center" valign="top"><!-- // Begin Template Body \\ -->'
1294: . '<table border="0" cellpadding="0" cellspacing="0" id="templateBody" width="600"><tbody><tr>'
1295: . '<td valign="top"><!-- // Begin Module: Standard Content \\ -->'
1296: . '<table border="0" cellpadding="20" cellspacing="0" width="100%"><tbody>';
1297:
1298: $params = array();
1299:
1300: $userRecord = X2Model::model('Profile')->findByPk($userId);
1301: $params[':username'] = $userRecord->username;
1302:
1303: $parsedFilters = Events::parseFilters($filters, $params);
1304:
1305: $visibilityCondition = $parsedFilters['conditions']['visibility'];
1306: $accessCriteria = Events::model ()->getAccessCriteria ();
1307: $userCondition = $parsedFilters['conditions']['users'];
1308: $typeCondition = $parsedFilters['conditions']['types'];
1309: $subtypeCondition = $parsedFilters['conditions']['subtypes'];
1310:
1311: $condition = "type!='comment' AND (type!='action_reminder' " .
1312: "OR user=:username) AND " .
1313: "(type!='notif' OR user=:username)" .
1314: $visibilityCondition . $userCondition . $typeCondition . $subtypeCondition .
1315: ' AND ('.$accessCriteria->condition.')';
1316: switch ($range) {
1317: case 'daily':
1318: $timeRange = 24 * 60 * 60;
1319: break;
1320: case 'weekly':
1321: $timeRange = 7 * 24 * 60 * 60;
1322: break;
1323: case 'monthly':
1324: $timeRange = 30 * 24 * 60 * 60;
1325: break;
1326: default:
1327: $timeRange = 24 * 60 * 60;
1328: break;
1329: }
1330: $condition .= " AND timestamp BETWEEN " . (time() - $timeRange) . " AND " . time();
1331:
1332: $topTypes = Yii::app()->db->createCommand()
1333: ->select('type, COUNT(type)')
1334: ->from('x2_events')
1335: ->where($condition, array_merge ($params, $accessCriteria->params))
1336: ->group('type')
1337: ->order('COUNT(type) DESC')
1338: ->limit(5)
1339: ->queryAll();
1340:
1341: $topUsers = Yii::app()->db->createCommand()
1342: ->select('user, COUNT(user)')
1343: ->from('x2_events')
1344: ->where($condition, array_merge ($params, $accessCriteria->params))
1345: ->group('user')
1346: ->order('COUNT(user) DESC')
1347: ->limit(5)
1348: ->queryAll();
1349:
1350: $msg .= "<tr><td style='text-align:center;'>";
1351: $msg .= "<div>" . Yii::t('profile', "Here's your {range} update on what's been going on in X2Engine!", array(
1352: '{range}' => Yii::t('profile', $range))) . "</div><br>"
1353: . "<div>Time Range: <em>" . Formatter::formatDateTime(time() - $timeRange) . "</em> to <em>" . Formatter::formatDateTime(time()) . "</em></div>";
1354: $msg .= "</tr></td>";
1355:
1356: $msg .= "<tr><td><table width='100%'><tbody>";
1357: $msg .= "<tr><th>" . Yii::t('profile', "Top Activity") . "</th><th>" . Yii::t('profile', "Top Users") . "</th></tr>";
1358: for ($i = 0; $i < 5; $i++) {
1359: $msg .= "<tr><td style='text-align:center;'>";
1360: if (isset($topTypes[$i])) {
1361: $type = Events::parseType($topTypes[$i]['type']);
1362: $count = $topTypes[$i]['COUNT(type)'];
1363: $msg .= $count . " " . $type;
1364: }
1365: $msg .= "</td><td style='text-align:center;'>";
1366: if (isset($topUsers[$i]) && $topUsers[$i]['COUNT(user)'] > 0) {
1367: $username = User::getUserLinks($topUsers[$i]['user'], false, true);
1368: $count = $topUsers[$i]['COUNT(user)'];
1369: $msg .= $count . " " . Yii::t('profile', "events from") . " " . $username . ".";
1370: }
1371: $msg .= "</td></tr>";
1372: }
1373: $msg .= "</tbody></table></td></tr>";
1374: $msg .= "<tr><td style='text-align:center'><hr width='60%'>";
1375: $msg .= "<tr><td style='text-align:center;'>" .
1376: Yii::t('profile', "Here's the {limit} most recent items on the Activity Feed.", array('{limit}' => $limit))
1377: . "</td></tr>";
1378: $msg .= "</td></tr>";
1379: $msg .= "<tr><td style='text-align:center'><hr width='60%'><table><tbody>";
1380: $events = new CActiveDataProvider('Events', array(
1381: 'criteria' => array(
1382: 'condition' => $condition,
1383: 'order' => 'timestamp DESC',
1384: 'params' => array_merge ($params, $accessCriteria->params),
1385: ),
1386: 'pagination' => array(
1387: 'pageSize' => $limit
1388: ),
1389: ));
1390:
1391: foreach ($events->getData() as $event) {
1392: $msg .= "<tr>";
1393: $avatar = Yii::app()->db->createCommand()
1394: ->select('avatar')
1395: ->from('x2_profile')
1396: ->where('username=:user', array(':user' => $event->user))
1397: ->queryScalar();
1398: if (!empty($avatar) && file_exists($avatar)) {
1399: $avatar = Profile::renderAvatarImage($id, 45, 45);
1400: } else {
1401: $avatar = X2Html::x2icon('profile-large',
1402: array(
1403: 'class' => 'avatar-image default-avatar',
1404: 'style' => "font-size: ${dimensionLimit}px",
1405: ));
1406: }
1407: $typeFile = $event->type;
1408: if (in_array($event->type, array('email_sent', 'email_opened'))) {
1409: if (in_array($event->subtype, array('quote', 'invoice')))
1410: $typeFile .= "_{$event->subtype}";
1411: }
1412: if ($event->type == 'record_create') {
1413: switch ($event->subtype) {
1414: case 'call':
1415: $typeFile = 'voip_call';
1416: break;
1417: case 'time':
1418: $typeFile = 'log_time';
1419: break;
1420: }
1421: }
1422: $img = $avatar;
1423: if (file_exists(Yii::app()->theme->getBasePath() . '/images/eventIcons/' . $typeFile . '.png')) {
1424: $imgFile = Yii::app()->getAbsoluteBaseUrl() . '/themes/' . Yii::app()->theme->getName() . '/images/eventIcons/' . $typeFile . '.png';
1425: $img = CHtml::image($imgFile, '',
1426: array(
1427: 'style' => 'width:45px;height:45px;float:left;margin-right:5px;',
1428: ));
1429: }
1430:
1431: $msg .= "<td>" . $img . "</td>";
1432: $msg .= "<td style='text-align:left'><span class='event-text'>" . $event->getText(array('requireAbsoluteUrl' => true), array('style' => 'text-decoration:none;')) . "</span></td>";
1433: $msg .= "</tr>";
1434: }
1435: $msg .= "</tbody></table></td></tr>";
1436:
1437: $msg .= "<tr><td style='text-align:center'><hr width='60%'><table><tbody>";
1438: $msg .= Yii::t('profile', "To stop receiving this report, ") . CHtml::link(Yii::t('profile', 'click here'), Yii::app()->getAbsoluteBaseUrl() . '/index.php/profile/deleteActivityReport?id=' . $eventId . '&deleteKey=' . $deleteKey);
1439: $msg .= "</tbody></table></td></tr>";
1440:
1441: $msg .= '</tbody></table></td></tr></tbody></table></td></tr>';
1442:
1443: $msg .= "<tbody></table></td></tr></tbody></table></center></body></html></div>";
1444:
1445: return $msg;
1446: }
1447:
1448: public function isTypeFeed () {
1449: return $this->type === 'feed' || $this->type === 'structured-feed';
1450: }
1451:
1452: protected function beforeSave() {
1453: if (empty($this->timestamp))
1454: $this->timestamp = time();
1455: $this->lastUpdated = time();
1456: if (!empty($this->user) && $this->isNewRecord) {
1457: $eventsData = X2Model::model('EventsData')->findByAttributes(array('type' => $this->type, 'user' => $this->user));
1458: if (isset($eventsData)) {
1459: $eventsData->count++;
1460: } else {
1461: $eventsData = new EventsData;
1462: $eventsData->user = $this->user;
1463: $eventsData->type = $this->type;
1464: $eventsData->count = 1;
1465: }
1466: $eventsData->save();
1467: }
1468: if ($this->type == 'record_deleted') {
1469: $this->text = preg_replace('/(<script(.*?)>|<\/script>)/', '', $this->text);
1470: }
1471: return parent::beforeSave();
1472: }
1473:
1474: protected function beforeDelete() {
1475: if (!empty($this->children)) {
1476: foreach ($this->children as $child) {
1477: $child->delete();
1478: }
1479: }
1480: return parent::beforeDelete();
1481: }
1482:
1483: 1484: 1485:
1486: public function attributeLabels() {
1487: return array(
1488: 'id' => Yii::t('admin', 'ID'),
1489: 'type' => Yii::t('admin', 'Type'),
1490: 'text' => Yii::t('admin', 'Text'),
1491: 'associationType' => Yii::t('admin', 'Association Type'),
1492: 'associationId' => Yii::t('admin', 'Association ID'),
1493: );
1494: }
1495:
1496: }
1497: