remove old readme
[atutor.git] / mods / _standard / social / lib / classes / Application.class.php
1 <?php
2 /****************************************************************/
3 /* ATutor                                                                                                               */
4 /****************************************************************/
5 /* Copyright (c) 2002-2009                                                                              */
6 /* Inclusive Design Institute                                   */
7 /* http://atutor.ca                                                                                             */
8 /*                                                              */
9 /* This program is free software. You can redistribute it and/or*/
10 /* modify it under the terms of the GNU General Public License  */
11 /* as published by the Free Software Foundation.                                */
12 /****************************************************************/
13 // $Id$
14
15 require_once(dirname(__FILE__) . '/Applications.class.php');
16 require_once(dirname(__FILE__) .'/../SecurityToken.php');
17 require_once(dirname(__FILE__) .'/../BlobCrypter.php');
18 require_once(dirname(__FILE__) .'/../Crypto.php');
19 require_once(dirname(__FILE__) .'/../BasicSecurityToken.php');
20 require_once(dirname(__FILE__) .'/../BasicBlobCrypter.php');
21
22 /**
23  * Object for Application, (aka Gadgets)
24  */
25 class Application extends Applications{
26         var $id;        //application id
27         var $url, $title, $height, $screenshot, $thumbnail, $author, $author_email, $description, $settings, $views;
28         var $version;
29
30         //constructor
31         function Application ($id=0){
32                 if ($id!=0){
33                         $this->id = $id;
34                         $this->getApplicationPrefs();   
35                 }
36         }
37
38         /* 
39          * Add application by URL
40          * @param       object          gadget object retrieved from JSON + cURL
41          */
42         function addApplication($gadget_obj){ 
43                 global $db, $addslashes;
44                 //TODO: Many more fields to add
45 //              $id                                             = $gadget_obj['moduleId'];   //after i change the URL to the key.
46                 $author                                 = $addslashes($gadget_obj->author);
47                 $author_location                = $addslashes($gadget_obj->authorLocation);
48                 $author_email                   = $addslashes($gadget_obj->authorEmail);
49                 $description                    = $addslashes($gadget_obj->description);
50                 $screenshot                             = $addslashes($gadget_obj->screenshot);
51                 $thumbnail                              = $addslashes($gadget_obj->thumbnail);
52                 $title                                  = $addslashes($gadget_obj->title);
53                 $height                                 = intval($gadget_obj->height);
54                 $module_id                              = intval($gadget_obj->module_id);
55                 $url                                    = $addslashes($gadget_obj->url);
56                 $userPrefs                              = $addslashes(serialize($gadget_obj->userPrefs));
57                 $views                                  = $addslashes(serialize($gadget_obj->views));
58                 $scrolling                              = intval(($gadget_obj->scrolling=='true'?1:0));
59
60                 //determine next id
61                 $sql = 'SELECT MAX(id) AS max_id FROM '.TABLE_PREFIX.'social_applications';
62                 $result = mysql_query($sql, $db);
63                 if ($result){
64                         $row = mysql_fetch_assoc($result);
65                         $id = $row['max_id'] + 1;
66                 } else {
67                         $id = 1;
68                 }
69                 $member_id = $_SESSION['member_id'];
70
71                 $sql = 'INSERT INTO '.TABLE_PREFIX."social_applications (id, url, title, height, scrolling, screenshot, thumbnail, author, author_email, description, settings, views, last_updated) VALUES ($id, '$url', '$title', $height, $scrolling, '$screenshot', '$thumbnail', '$author', '$author_email', '$description', '$userPrefs', '$views', NOW())";
72                 $result = mysql_query($sql, $db);
73                 
74                 //This application is already in the database, get its ID out
75                 if (!$result){                  
76                         $sql = 'SELECT id, UNIX_TIMESTAMP(last_updated) AS last_updated FROM '.TABLE_PREFIX."social_applications WHERE url='$url'";
77                         $result = mysql_query($sql, $db);
78                         $row = mysql_fetch_assoc($result);
79                         $id = $row['id'];
80
81                         //Update the gadget
82                         //TODO: Needs some sort of comparing instead of blinding updating everytime. Version(can't find any)? Date(need another field in db?)
83                         //Use TIMESTAMP for now, but i perfer version #.
84                         //If the gadget is SOCIAL_APPLICATION_UPDATE_SCHEDULE days old, update it
85                         if (abs($row['last_updated']) < strtotime('-'.SOCIAL_APPLICATION_UPDATE_SCHEDULE.' day')){
86                                 $sql = 'UPDATE '.TABLE_PREFIX."social_applications SET title='$title', height=$height, scrolling=$scrolling, screenshot='$screenshot', thumbnail='$thumbnail', author='$author', author_email='$author_email', description='$description', settings='$userPrefs', views='$views', last_updated=NOW() WHERE url='$url'";
87                                 $result = mysql_query($sql, $db);
88                                 //echo $sql;
89                         }
90                 } 
91
92                 //Add a record into application_member table for mapping
93                 $this->addMemberApplication($member_id, $id);
94                 
95                 // Post gadget information to www.atutor.ca for sharing
96                 $this->saveApplicationForShare($gadget_obj->url, $gadget_obj->title, $gadget_obj->height,
97                         $gadget_obj->screenshot, $gadget_obj->thumbnail, $gadget_obj->description,
98                         $gadget_obj->author, $gadget_obj->authorEmail);
99         }
100
101
102         /**
103          * Add this application to the member's application list
104          * @param       int             member_id
105          * @param       int             application_id
106          */
107         function addMemberApplication($member_id, $app_id){
108                 global $db;
109
110                 $member_id = intval($member_id);
111                 $app_id = intval($app_id);
112
113                 $sql = 'INSERT INTO '.TABLE_PREFIX."social_members_applications (member_id, application_id) VALUES ($member_id, $app_id)";
114                 $result = mysql_query($sql, $db);
115
116                 if ($result){
117                         //Add this to the home page
118                         $home_settings = $this->getHomeDisplaySettings();
119                         $home_settings[$app_id] = 1;    //manually set this application
120                         $this->setHomeDisplaySettings($home_settings);
121
122                         $act = new Activity();          
123                         $act->addActivity($_SESSION['member_id'], '', $app_id);
124                         unset($act);
125                 }
126         }
127
128
129         /**
130          * Parse application details
131          * @return      array of the attributes
132          *
133          */
134         function parseModulePrefs($app_url){
135                 //parse all the attributes of the <ModulePrefs> tag
136                 //and save everything in the object.
137                 $securityToken = BasicSecurityToken::createFromValues(1, 1, 0, AT_BASE_HREF, urlencode($app_url), 0);
138                 $gadget = $this->fetch_gadget_metadata($app_url, $securityToken);
139                  return $gadget->gadgets;
140         }
141
142
143         // Restful - JSON CURL data transfer
144         private function fetch_gadget_metadata($app_url, $securityToken) {
145                 $request = json_encode(array(
146                         'context' => array('country' => 'US', 'language' => 'en', 'view' => 'default', 
147                                 'container' => 'atutor'), 
148                         'gadgets' => array(array('url' => $app_url, 'moduleId' => $this->getModuleId()))));
149                 $ch = curl_init();
150                 curl_setopt($ch, CURLOPT_URL, AT_SHINDIG_URL.'/gadgets/metadata?st=' . urlencode(base64_encode($securityToken->toSerialForm())));;
151                 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
152                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
153                 curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
154                 curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
155                 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 4);
156                 curl_setopt($ch, CURLOPT_TIMEOUT, 20);
157                 curl_setopt($ch, CURLOPT_POST, 1);
158                 curl_setopt($ch, CURLOPT_POSTFIELDS, 'request=' . urlencode($request));
159                 $content = @curl_exec($ch);
160                 return json_decode($content);
161         }
162
163
164         /**
165          * Add application perferences into the table.
166          * @param       int             member id
167          * @param       string  hash's key, usually the name of the application
168          * @param       string  hash's value, contains key, value, and st.
169          * @return      true(1) if the perference has been updated, false(0) otherwise.
170          */
171         function setApplicationSettings($member_id, $key, $value){
172                 global $addslashes, $db;
173
174                 $app_id         = $this->id;
175                 $member_id      = intval($member_id);           
176                 $key            = $addslashes($key);
177                 $value          = $addslashes($value);
178
179                 $sql = 'INSERT INTO '.TABLE_PREFIX."social_application_settings (application_id, member_id, name, value) VALUES ($app_id, $member_id, '$key', '$value') ON DUPLICATE KEY UPDATE value='$value'";
180                 $result = mysql_query($sql, $db);
181
182                 //TODO: Might want to add something here to throw appropriate exceptions
183                 return $result;
184         }
185
186
187         /**
188          * Get member's applications
189          * @param       int             the member id
190          */
191         function getMemberApplications($member_id){
192                 global $db;
193                 $result = array();
194
195                 $member_id = intval($member_id);
196                 $sql = 'SELECT * FROM '.TABLE_PREFIX.'social_members_applications WHERE member_id='.$member_id;
197                 $rs = mysql_query($sql, $db);
198                 if ($rs){
199                         while($row = mysql_fetch_assoc($rs)){
200                                 $result[] = $row['app_id'];
201                         }
202                 }
203                 return $result;
204         }
205
206
207         /**
208          * Get user perferences for this application
209          * @return      array
210          */
211         function getApplicationSettings($member_id){
212                 global $db;
213                 $result = array();
214                 $member_id = intval($member_id);
215
216                 $sql = 'SELECT * FROM '.TABLE_PREFIX."social_application_settings WHERE member_id=$member_id AND application_id=".$this->id;
217                 $rs = mysql_query($sql);
218                 if ($rs){
219                         //loop cause an application can have multiple pairs of key=>value
220                         while ($row = mysql_fetch_assoc($rs)){
221                                 $result[$row['name']] = $row['value'];
222                         }
223                 }
224                 return $result;
225         }
226
227         function getId(){
228                 return $this->id;
229         }
230
231         function getUrl(){
232                 return $this->url;
233         }
234
235         function getTitle(){
236                 return $this->title;
237         }
238
239         function getModuleId(){
240                 return intval($this->module_id);
241         }
242
243         function getHeight(){
244                 if ($this->height==0){
245                         return 600;
246                 }
247                 return $this->height;
248         }
249
250         function getScreenshot(){
251                 return $this->screenshot;
252         }
253
254         function getThumbnail(){
255                 //check if this thumbnail link is a relative link
256                 $url = parse_url($this->thumbnail);
257                 if (!isset($url['scheme']) && !isset($url['host'])){
258                         $orig_url = parse_url($this->getUrl());
259                         return $orig_url['scheme'].'://'.$orig_url['host'].$this->thumbnail;
260                 }
261                 return $this->thumbnail;
262         }
263
264         function getAuthor(){
265                 return $this->author;
266         }
267
268         function getAuthorEmail(){
269                 return $this->author_email;
270         }
271
272         function getAuthorLocation(){
273                 return $this->author_location;
274         }
275
276         function getDescription(){
277                 return $this->description;
278         }
279
280         function getScrolling(){
281                 return ($this->scrolling==1?'yes':'no');
282         }
283
284         function getSettings(){
285                 return unserialize($this->settings);
286         }
287
288         function getViews(){
289                 return unserialize($this->views);
290         }
291
292         /** 
293          * Return iframe URL based on the given parameters
294          * @param       int                     owner id
295          * @param       string          avaiable options are 'profile', 'canvas'
296          *                                              http://code.google.com/apis/orkut/docs/orkutdevguide/orkutdevguide-0.8.html#ops_mode
297          * @param       string          extra application parameters
298          * @return      iframe url
299          */
300         function getIframeUrl($oid, $view='default', $appParams=''){
301
302                 $app_settings = $this->getSettings();
303                 $user_settings = $this->getApplicationSettings($_SESSION['member_id']);
304
305                 //retrieve user preferences
306                 foreach ($app_settings as $key => $setting) {
307                         if (! empty($key)) {
308                           $value = isset($user_settings[$key]) ? $user_settings[$key] : (isset($setting->default) ? $setting->default : null);
309                           if (isset($user_settings[$key])) {
310                                 unset($user_settings[$key]);
311                           }
312                           //shindig doesn't like ';', it only takes '&' as of Apr 6th, 2009
313                           //$prefs .= SEP.'up_' . urlencode($key) . '=' . urlencode($value);
314                           $prefs .= '&up_' . urlencode($key) . '=' . urlencode($value);
315                         }
316                 }
317                 foreach ($user_settings as $name => $value) {
318                         // if some keys _are_ set in the db, but not in the gadget metadata, we still parse them on the url
319                         // (the above loop unsets the entries that matched  
320                         if (! empty($value) && ! isset($appParams[$name])) {
321                         //shindig doesn't like ';', it only takes '&' as of Apr 6th, 2009
322                         //$prefs .= SEP.'up_' . urlencode($name) . '=' . urlencode($value);
323                         $prefs .= '&up_' . urlencode($name) . '=' . urlencode($value);
324                         }
325                 }
326
327                 //generate security token
328                 $securityToken = BasicSecurityToken::createFromValues(($oid > 0?$oid:$_SESSION['member_id']), // owner
329                                                 $_SESSION['member_id'], // viewer
330                                                 $this->getId(), // app id
331                                                 'default', // domain key, shindig will check for php/config/<domain>.php for container specific configuration
332                                                 urlencode($this->getUrl()), // app url
333                                                 $this->getModuleId());// mod id
334 //debug($securityToken);
335 //TODO: 
336                 //   all the & should be using the constant "SEP", however, shingdig isn't parsing ";", 
337                 //   it only parses "&".  Once shindig fixed this, we gotta change it back to SEP
338                 //@harris July 23, 2009
339                 $url = AT_SHINDIG_URL.'/gadgets/ifr?' 
340                         . "bpc=1&synd=ATutor"                           //container name
341                         . "&container=default"          //container name
342                         . "&viewer=". $_SESSION['member_id']    //viewer ID
343                         . "&owner=" . $oid                      //owner ID
344                         . "&aid=" . $this->getId()                      //application id
345                         . "&mid=" . $this->getModuleId()        //module ID
346                         . "&country=US"                 //country code
347                         . "&lang=en"            //language code
348                         . "&view=" . $view      //canvas for this big thing, should be a variable
349                         . "&parent=" . urlencode("http://" . $_SERVER['HTTP_HOST']) . $prefs . (isset($appParams) ? '&view-params=' . urlencode($appParams) : '') //container URL
350                         . "&st=" . urlencode(base64_encode($securityToken->toSerialForm())) //encrypted token
351                         . "&v=" . $this->getVersion()   //cache busting md5 of the gadget xml
352                         . "&url=" . urlencode($this->getUrl()) //url of gadgets xml
353                         . "#rpctoken=" . rand(0, getrandmax());  //random unique number
354                 return $url;
355         }
356
357         /**
358          * Returns the cache busting md5 of the gadget XML 
359          * @return      md5 of the xml content.
360          */
361         function getVersion(){
362                 //use the skeleton of the XML as version
363                 //if it changed, then version is changed.
364                 $xml = file_get_contents(($this->getUrl()));
365                 return md5($xml);
366         }
367
368
369         /**
370          * Retrieve all information about this gadget and save it in the object
371          * @private
372          */
373         function getApplicationPrefs(){
374                 global $db;
375
376                 $sql = 'SELECT * FROM '.TABLE_PREFIX.'social_applications WHERE id='.$this->id;
377                 $rs = mysql_query($sql);
378
379                 if ($rs){
380                         $row = mysql_fetch_assoc($rs);
381                         //assign values
382                         $this->url                      = $row['url'];
383                         $this->title            = $row['title'];
384                         $this->height           = $row['height'];
385                         $this->scrolling        = $row['scrolling'];
386                         $this->screenshot       = $row['screenshot'];
387                         $this->thumbnail        = $row['thumbnail'];
388                         $this->author           = $row['author'];
389                         $this->author_email     = $row['author_email'];
390                         $this->description      = $row['description'];
391                         $this->settings         = $row['settings'];
392                         $this->views            = $row['views'];
393                         $this->last_updated     = $row['last_updated'];
394                 }
395         }
396
397         /** 
398          * Delete an application
399          */
400         function deleteApplication(){
401                 global $db;
402
403                 //delete application mapping
404                 $sql = 'DELETE FROM '.TABLE_PREFIX.'social_members_applications WHERE application_id='.$this->id.' AND member_id='.$_SESSION['member_id'];
405                 $rs = mysql_query($sql);
406
407                 //delete application data?
408                 $sql = 'DELETE FROM '.TABLE_PREFIX.'social_application_settings WHERE application_id='.$this->id.' AND member_id='.$_SESSION['member_id'];
409                 $rs = mysql_query($sql);
410
411                 //delete application settings
412                 $home_settings = $this->getHomeDisplaySettings();
413                 if (isset($home_settings[$this->id])){                  
414                         unset($home_settings[$this->id]);
415                         $this->setHomeDisplaySettings($home_settings);
416                 }
417
418                 return $rs;
419         }
420         
421         /** 
422          * Save gadget informaiton into atutor.ca/gadget_log.php to share among ATutor users
423          */
424         function saveApplicationForShare($url, $title, $height, $screenshot, $thumbnail, $description, $author, $authorEmail){
425                 $request = "&url=".urlencode($url)."&title=".urlencode($title).
426                            "&height=".urlencode($height)."&screenshot=".urlencode($screenshot).
427                            "&thumbnail=".urlencode($thumbnail)."&desc=".urlencode($description).
428                            "&author=".urlencode($author)."&authorEmail=".urlencode($authorEmail);
429                 
430                 $header = "POST /gadget_log.php HTTP/1.1\r\n";
431                 $header .= "Host: atutor.ca\r\n";
432                 $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
433                 $header .= "Content-Length: " . strlen($request) . "\r\n\r\n";
434                 $fp = fsockopen('www.atutor.ca', 80, $errno, $errstr, 30);
435
436                 if ($fp) {
437                         fputs($fp, $header . $request . "\r\n\r\n");
438                         fclose($fp);
439                 }
440         }
441 }
442 ?>