fix for external invitations
[tine20] / tine20 / Calendar / js / iMIPDetailsPanel.js
1 /*
2  * Tine 2.0
3  * 
4  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
5  * @author      Cornelius Weiss <c.weiss@metaways.de>
6  * @copyright   Copyright (c) 2011-2012 Metaways Infosystems GmbH (http://www.metaways.de)
7  */
8 Ext.ns('Tine.Calendar');
9
10 /**
11  * display panel for MIME type text/calendar
12  * 
13  * NOTE: this panel is registered on Tine.Calendar::init
14  * 
15  * @namespace   Tine.Calendar
16  * @class       Tine.Calendar.iMIPDetailsPanel
17  * @author      Cornelius Weiss <c.weiss@metaways.de>
18  * @constructor
19  */
20 Tine.Calendar.iMIPDetailsPanel = Ext.extend(Tine.Calendar.EventDetailsPanel, {
21     /**
22      * @cfg {Object} preparedPart
23      * server prepared text/calendar iMIP part 
24      */
25     preparedPart: null,
26     
27     /**
28      * @property actionToolbar
29      * @type Ext.Toolbar
30      */
31     actionToolbar: null,
32     
33     /**
34      * @property iMIPrecord
35      * @type Tine.Calendar.Model.iMIP
36      */
37     iMIPrecord: null,
38     
39     /**
40      * @property statusActions
41      * @type Array
42      */
43     statusActions:[],
44     
45     /**
46      * init this component
47      */
48     initComponent: function() {
49         this.app = Tine.Tinebase.appMgr.get('Calendar');
50         
51         this.iMIPrecord = new Tine.Calendar.Model.iMIP(this.preparedPart.preparedData);
52         if (! this.iMIPrecord.get('event') || ! Ext.isFunction(this.iMIPrecord.get('event').beginEdit)) {
53             this.iMIPrecord.set('event', Tine.Calendar.backend.recordReader({
54                 responseText: Ext.util.JSON.encode(this.preparedPart.preparedData.event)
55             }));
56         }
57         
58         this.initIMIPToolbar();
59         
60         this.on('afterrender', this.showIMIP, this);
61         
62         Tine.Calendar.iMIPDetailsPanel.superclass.initComponent.call(this);
63     },
64     
65     /**
66      * (re) prepare IMIP
67      */
68     prepareIMIP: function() {
69         this.iMIPclause.setText(this.app.i18n._('Checking Calendar Data...'));
70         
71         Tine.Calendar.iMIPPrepare(this.iMIPrecord.data, function(result, response) {
72             this.preparedPart.preparedData = result;
73             if (response.error) {
74                 // give up!
75                 this.iMIPrecord.set('preconditions', {'GENERIC': 'generic problem'});
76             } else {
77                 this.iMIPrecord = new Tine.Calendar.Model.iMIP(result);
78                 this.iMIPrecord.set('event', Tine.Calendar.backend.recordReader({
79                     responseText: Ext.util.JSON.encode(result.event)
80                 }));
81             }
82             
83             this.showIMIP();
84         }, this);
85     },
86     
87     /**
88      * process IMIP
89      * 
90      * @param {String} status
91      */
92     processIMIP: function(status, range) {
93         if (this.iMIPrecord.get('event').isRecurBase() && status != 'ACCEPTED' && !range) {
94             Tine.widgets.dialog.MultiOptionsDialog.openWindow({
95                 title: this.app.i18n._('Reply to Recurring Event'),
96                 questionText: this.app.i18n._('You are responding to an recurring event. What would you like to do?'),
97                 height: 170,
98                 scope: this,
99                 options: [
100                     {text: this.app.i18n._('Respond to whole series'), name: 'series'},
101                     {text: this.app.i18n._('Do not respond'), name: 'cancel'}
102                 ],
103                 
104                 handler: function(option) {
105                     if (option != 'cancel') {
106                         this.processIMIP(status, option);
107                     }
108                 }
109             });
110             return;
111         }
112         
113         Tine.log.debug('Tine.Calendar.iMIPDetailsPanel::processIMIP status: ' + status);
114         this.getLoadMask().show();
115         
116         Tine.Calendar.iMIPProcess(this.iMIPrecord.data, status, function(result, response) {
117             this.preparedPart.preparedData = result;
118             if (response.error) {
119                 // precondition changed?  
120                 return this.prepareIMIP();
121             }
122             
123             // load result
124             this.iMIPrecord = new Tine.Calendar.Model.iMIP(result);
125             this.iMIPrecord.set('event', Tine.Calendar.backend.recordReader({
126                 responseText: Ext.util.JSON.encode(result.event)
127             }));
128             this.showIMIP();
129         }, this);
130     },
131     
132     /**
133      * iMIP action toolbar
134      */
135     initIMIPToolbar: function() {
136         var singleRecordPanel = this.getSingleRecordPanel();
137         
138         this.actions = [];
139         this.statusActions = [];
140         
141         Tine.Tinebase.widgets.keyfield.StoreMgr.get('Calendar', 'attendeeStatus').each(function(status) {
142             // NEEDS-ACTION is not appropriate in iMIP context
143             if (status.id == 'NEEDS-ACTION') return;
144             
145             this.statusActions.push(new Ext.Action({
146                 text: status.get('i18nValue'),
147                 handler: this.processIMIP.createDelegate(this, [status.id]),
148                 icon: status.get('icon')
149             }));
150         }, this);
151         
152         this.actions = this.actions.concat(this.statusActions);
153         
154         // add more actions here (no spam / apply / crush / send event / ...)
155         
156         this.iMIPclause = new Ext.Toolbar.TextItem({
157             text: ''
158         });
159         this.tbar = this.actionToolbar = new Ext.Toolbar({
160             items: [{
161                     xtype: 'tbitem',
162                     cls: 'CalendarIconCls',
163                     width: 16,
164                     height: 16,
165                     style: 'margin: 3px 5px 2px 5px;'
166                 },
167                 this.iMIPclause,
168                 '->'
169             ].concat(this.actions)
170         });
171     },
172     
173     /**
174      * show/layout iMIP panel
175      */
176     showIMIP: function() {
177         var singleRecordPanel = this.getSingleRecordPanel(),
178             preconditions = this.iMIPrecord.get('preconditions'),
179             method = this.iMIPrecord.get('method'),
180             event = this.iMIPrecord.get('event'),
181             existingEvent = this.iMIPrecord.get('existing_event'),
182             myAttenderRecord = event.getMyAttenderRecord(),
183             myAttenderstatus = myAttenderRecord ? myAttenderRecord.get('status') : null;
184             
185         // show container from existing event if exists
186         if (existingEvent && existingEvent.container_id) {
187             event.set('container_id', existingEvent.container_id);
188         }
189             
190         // reset actions
191         Ext.each(this.actions, function(action) {action.setHidden(true)});
192         
193         // check preconditions
194         if (preconditions) {
195             if (preconditions.hasOwnProperty('EVENTEXISTS')) {
196                 this.iMIPclause.setText(this.app.i18n._("The event of this message does not exist"));
197             }
198             
199             else if (preconditions.hasOwnProperty('ORIGINATOR')) {
200                 // display spam box -> might be accepted by user?
201                 this.iMIPclause.setText(this.app.i18n._("The sender is not authorised to update the event"));
202             }
203             
204             else if (preconditions.hasOwnProperty('RECENT')) {
205 //            else if (preconditions.hasOwnProperty('TOPROCESS')) {
206                 this.iMIPclause.setText(this.app.i18n._("This message is already processed"));
207             }
208             
209             else if (preconditions.hasOwnProperty('ATTENDEE')) {
210                 // party crush button?
211                 this.iMIPclause.setText(this.app.i18n._("You are not an attendee of this event"));
212             } 
213             
214             else {
215                 this.iMIPclause.setText(this.app.i18n._("Unsupported message"));
216             }
217         } 
218         
219         // method specific text / actions
220         else {
221             switch (method) {
222                 case 'REQUEST':
223                     if (! myAttenderRecord) {
224                         // might happen in shared folders -> we might want to become a party crusher?
225                         this.iMIPclause.setText(this.app.i18n._("This is an event invitation for someone else."));
226                     } else if (myAttenderstatus !== 'NEEDS-ACTION') {
227                         this.iMIPclause.setText(this.app.i18n._("You have already replied to this event invitation."));
228                     } else {
229                         this.iMIPclause.setText(this.app.i18n._('You received an event invitation. Set your response to:'));
230                         Ext.each(this.statusActions, function(action) {action.setHidden(false)});
231                     }
232                     break;
233                     
234                     
235                 case 'REPLY':
236                     // Someone replied => autoprocessing atm.
237                     this.iMIPclause.setText(this.app.i18n._('An invited attendee responded to the invitation.'));
238                     break;
239                     
240                 default:
241                     this.iMIPclause.setText(this.app.i18n._("Unsupported method"));
242                     break;
243             }
244         }
245         
246         this.getLoadMask().hide();
247         singleRecordPanel.setVisible(true);
248         singleRecordPanel.setHeight(150);
249         
250         if (existingEvent) {
251             this.record = Tine.Calendar.backend.recordReader({
252                 responseText: Ext.util.JSON.encode(existingEvent)
253             });
254         } else {
255             this.record = event;
256         }
257         singleRecordPanel.loadRecord(this.record);
258     }
259 });