1<?php
2/**
3 * DokuWiki Plugin asana (Action Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  pierre Viloutreix <pierre@elonet.fr>
7 */
8
9include "asana_fcts.php";
10include "../../../../inc/plugins.php";
11include "../../remote.php";
12//include "/usr/share/dokuwiki/inc/plugin.php";
13//include "/usr/share/dokuwiki/lib/plugins/remote.php";
14
15// must be run within Dokuwiki
16if (!defined('DOKU_INC')) die();
17
18class remote_plugin_asana_APILink extends DokuWiki_Remote_Plugin {
19
20    //url de l'API d'Asana, on la garni en fonction de la requete
21    var $url_base = "https://app.asana.com/api/1.0";
22
23
24    var $api_key = "";
25
26    //initialisation de l'objet de requete utilisant curl
27    var $ch;
28
29    //workspace par default
30    var $workspace = "";
31
32    //text to render
33    var $text = "";
34
35    var $workspaces = array();
36
37    var $projects = array();
38
39    var $assignees = array();
40
41    var $tags = array();
42
43    var $workspace_filter = array();
44
45
46    var $assignees_filter= array();
47
48
49    var $tags_filter= array();
50
51
52    var $projects_filter = array();
53
54    var $strings_filter = array();
55
56    /**
57     * Construct curl object to collecte Asana's intelligences
58     * Api from this user in prameter
59     **/
60    public function __construct(){
61        //echo "Initialisation de l'objet CURL\n";
62        $this->ch= curl_init();
63        //obtenir la réponse comme un return
64        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER , true);
65        //définie le header de la requete
66        curl_setopt($this->ch, CURLOPT_HTTPHEADER , array('Content-type: application/json'));
67        //définie option ssl
68        curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER , FALSE);
69
70
71    }
72
73    public function __destruct(){
74        curl_close($this->ch);
75    }
76
77
78    /**
79     * Register RPC methods and their arguments
80     */
81    public function _getMethods() {
82        return array(
83
84            'plugin.asana.connecte' => array(
85                'args'   => array('string'),
86                'return' => 'string',
87                'doc'    => "Connecte un user à son compte Asana via sa clé API"
88            ),
89            'plugin.asana.render_user' => array(
90                'args'   => array('string'),
91                'return' => 'string',
92                'doc'    => "Donne le rendu des taches Asana d'un user sous forme d'un tableau"
93            )
94        );
95    }
96
97
98    /**
99     * Connection à l\'api via la demande de clé api pour le site Asana
100     **/
101     function connect(){
102         $api_key_user = $this->getConf('api_key');
103         //echo "Définition de la clé API\n";
104         if( $api_key_user != "Asana's API key"){
105            $this->api_key = $api_key_user;
106        }
107        else {
108            return "<p> Vous devez spécifier une clé API d'Asana depuis le menu de configuration du plugin Asana.</p>";
109        }
110        //définie l'utilisateur et mdp ( ici pas de mdp)
111        curl_setopt($this->ch, CURLOPT_USERPWD , $this->api_key . ":");
112
113
114        $this->workspaces = $this->workspaces();
115
116        //ici on ira cherché le workspace contenu dans la partie conf
117        foreach( $this->workspaces as $work_key => $work_value ){
118            if( $work_key == $this->getConf('workspace')){
119                $this->workspace_filter['name']= $work_key;
120                $this->workspace_filter['id']=$work_value;
121            }
122        }
123
124        if(!empty($this->workspace_filter)){
125            $this->projects = $this->workspace_projects($this->workspace_filter['id']);
126            $this->assignees = $this->workspace_users($this->workspace_filter['id']);
127            $this->tags = $this->workspace_tags($this->workspace_filter['id']);
128        }
129        return "";
130    }
131
132    /*
133    /**
134     * render le tableau contenant les infromations sur les taches
135     * le format du render text est surrement à modifier
136
137     **/
138    function render_user(){
139        if(empty($this->workspace_filter)){
140            return "<p>Vous devez spécifier un nom de workspace. Soit dans la configuration du plugin. Soit dans la syntaxe.</p>";
141        }
142        else{
143            $text = "<div>";
144            $text = $text . "<h1> Tâches Asana ( Asana's Tasks ) </h1><br/>";
145            $text = $text . "<h2>". $this->workspace_filter['name'] . "</h2><br/>";
146            $text = $text . "<table>".$this->render_workspaces($this->workspace_filter['id'])."</table>";
147            $text = $text . "<br/><br/>";
148            return $text."</div>";
149        }
150    }
151
152    /**
153     * render un worspace, c'est à dire créé un tableau
154     * met dans text les données structurant le tableau
155     **/
156
157    function render_workspaces($workspace){;
158        $text =  "<tr><td>Project</td><td> Task Name</td><td> Assignee </td><td> Due date </td><td> Comments/Tags </td></tr>";
159        $tasks = array();
160        if( empty($this->assignees_filter)){
161            if(empty($this->projects_filter)){
162                //non assignee non project
163                $this->projects = $this->workspace_projects($workspace);
164                foreach( $this->projects as $project_key => $project_value ){
165                    $tasks_current = $this->project_tasks($project_value);
166                    foreach($tasks_current as $task_key => $task_value){
167                        $task_value['project']=$project_key;
168                        $tasks_current[$task_key]=$task_value;
169                    }
170                    $tasks = array_merge($tasks,$tasks_current);
171
172                }
173            }
174            else{
175                //non assignee project
176                foreach( $this->projects_filter as $project_key => $project_value){
177                    $tasks_current = $this->project_tasks($project_value);
178                    foreach($tasks_current as $task_key => $task_value){
179                        $task_value['project']=$project_key;
180                        $tasks_current[$task_key]=$task_value;
181                    }
182                    $tasks = array_merge($tasks,$tasks_current);
183                }
184            }
185        }
186        else{
187            if(empty($this->projects_filter)){
188                //assignee non project
189                foreach( $this->assignees_filter as $assignee){
190                    foreach( $this->projects as $project_key => $project_value ){
191                        $tasks_current = $this->project_tasks_assignee($project_value, $assignee);
192                        foreach($tasks_current as $task_key => $task_value){
193                            $task_value['project']=$project_key;
194                            $tasks_current[$task_key]=$task_value;
195                        }
196                        $tasks = array_merge($tasks,$tasks_current);
197                    }
198                }
199            }
200            else{
201                //assignee project
202                foreach( $this->projects_filter as $project_key => $project_value){
203                    foreach( $this->assignees_filter as $assignee){
204                        $tasks_current = $this->project_tasks_assignee($project_value,$assignee);
205                        //var_dump($tasks_current);
206                        foreach($tasks_current as $task_key => $task_value){
207                            $task_value['project']=$project_key;
208                            $tasks_current[$task_key]=$task_value;
209                        }
210
211                        $tasks = array_merge($tasks,$tasks_current);
212                    }
213                }
214            }
215        }
216        if( !empty($this->tags_filter)){
217            foreach($this->tags_filter as $tag_key => $tag_value){
218                $tasks = $this->tag_filter($tag_key,$tasks);
219            }
220        }
221
222        if( !empty($this->strings_filter)){
223            foreach($this->strings_filter as $string){
224                $tasks = $this->string_filter($string, $tasks);
225            }
226        }
227
228        $tasks = $this->due_date_sort($tasks);
229        foreach(  $tasks as $task){
230                $text .=  "<tr><td> ".$task['project'] . " </td><td> " . "<a href='https://app.asana.com/0/".$this->project_find($this->projects_filters,$task['project'])."/".$task['id']."' target='_blank'>".$task['name'] ."</a>". " </td><td> " .$task['assignee']['name'] . " </td><td> " . $task['due_date'] . " </td><td> " . $this->comment_head($task['id'],$this->render_comments($task['id']).$this->render_tags($task['tags']))." </td></tr>";
231        }
232        return $text;
233    }
234
235
236
237
238    /*
239     * donne le code html pour afficher les commentaires de chaque tâches
240     * on affiche une fenêtre modale contenant les commentaires sous forme de liste
241     **/
242    function comment_head($div_id,$text){
243        return "<html>
244                    <style>
245                    #comment".$div_id."{
246                        display: none;
247                        position: fixed;
248                        top:0;
249                        right:0;
250                        bottom:0;
251                        left:0;
252                        background-color: rgba(0, 0, 0, 0.5);
253                        z-index: 1000;
254                    }
255                    #comment".$div_id.":target{
256                        display: block;
257                    }
258                    #comment".$div_id." a{
259                        font-weight: bold;
260                        padding: 10px 25px;
261                        background-color: white;
262                        position: absolute;
263                        top: 25%;
264                        left: 50px;
265                    }
266                    </style>
267                    <div id='comment".$div_id."'>
268                        <a href='#noWhere' ><p>Fermer les commentaires</p>".$text."</a>
269                    </div>
270                    <p><a href='#comment".$div_id."'>Afficher le masque</a></p>
271                </html>";
272
273    }
274
275
276
277     /* render des commentaires d'une tache
278     * liste des textes des commentaires
279     **/
280
281    function render_comments($task){
282        $text = "<h2>Comments :</h2>";
283        $text .= "<ul>";
284        foreach( $this->task_comments($task) as $comment_key => $comment_value){
285            $text = $text . "<li>" . $comment_key . "</li>";
286        }
287
288        return $text."</ul>";
289    }
290
291
292    /**
293     * render des tags
294     * liste des noms de tags
295     **/
296
297    function render_tags($tags){
298        $text = "<h2>Tags :</h2>";
299        $text .= "<ul>";
300        foreach( $tags as $tag){
301            $text = $text . "<li>" . $tag['name'] . "</li>";
302        }
303        return $text."</ul>";
304    }
305
306
307    function addProjectFilter($project_target_name){
308        foreach($this->projects as $project_key => $project_value){
309            if($project_key==$project_target_name){
310               $this->projects_filter[$project_key]=$project_value;
311               return 1;
312           }
313       }
314       return 0;
315    }
316
317    function addAssigneeFilter($assignee_target_name){
318        foreach($this->assignees as $assignee_key => $assignee_value){
319            if($assignee_key==$assignee_target_name){
320               $this->assignees_filter[$assignee_key]=$assignee_value;
321               return 1;
322           }
323       }
324       return 0;
325    }
326
327    function addTagFilter($tag_target_name){
328        foreach($this->tags as $tag_key => $tag_value){
329            if($tag_key==$tag_target_name){
330               $this->tags_filter[$tag_key]=$tag_value;
331               return 1;
332           }
333       }
334       return 0;
335    }
336
337    function addStringFilter($string_filter){
338        $this->strings_filter[]= $string_filter;
339    }
340
341    function changeWorkspace($workspace_target_name){
342        foreach($this->workspaces as $work_key => $work_value){
343            if( $work_key == $workspace_target_name){
344                $this->workspace_filter = array( 'name' => $work_key , 'id' => $work_value );
345                $this->projects = $this->workspace_projects($this->workspace_filter['id']);
346                $this->assignees = $this->workspace_users($this->workspace_filter['id']);
347                $this->tags = $this->workspace_tags($this->workspace_filter['id']);
348                return 1;
349            }
350        }
351        return 0;
352    }
353
354    //donne la liste des workspace de l'utilisateur courant
355    function workspaces(){
356         curl_setopt($this->ch, CURLOPT_URL , $this->url_base."/users/me");
357         $data_rep = json_decode(curl_exec($this->ch),true);
358         //var_dump($data_rep);
359         $workspaces = array();
360         foreach($data_rep['data']['workspaces'] as $workspace){
361            $workspaces[$workspace['name']]=$workspace['id'];
362         }
363         return $workspaces;
364    }
365
366    // donne la liste des utilisateur du workspace spécifié
367    // retourne la liste sous forme clé : nom, valeur : id
368    function workspace_users($workspace_ID){
369		curl_setopt($this->ch, CURLOPT_URL , $this->url_base."/workspaces/".$workspace_ID."/users");
370		$data_rep = json_decode(curl_exec($this->ch),true);
371		$users = array();
372		foreach($data_rep['data'] as $nom){
373			$users[$nom['name']]=$nom['id'];
374		}
375		return $users;
376    }
377
378    //donne les projets d'un workspace donné
379    function workspace_projects($workspace_ID){
380		curl_setopt($this->ch, CURLOPT_URL , $this->url_base."/workspaces/".$workspace_ID."/projects");
381		$data_rep = json_decode(curl_exec($this->ch),true);
382		//var_dump($data_rep);
383		$projects = array();
384		foreach($data_rep['data'] as $project){
385			$projects[$project['name']]=$project['id'];
386		}
387
388		return $projects;
389    }
390
391    function workspace_tags($workspace_ID){
392        curl_setopt($this->ch, CURLOPT_URL , $this->url_base."/workspaces/".$workspace_ID."/tags");
393        $data_rep = json_decode(curl_exec($this->ch),true);
394        //var_dump($data_rep);
395        $tags = array();
396        foreach($data_rep['data'] as $tag){
397                $tags[$tag['name']]=$tag['id'];
398        }
399        return $tags;
400    }
401
402    //donne les tache d'un project selon un assignee
403    function project_tasks_assignee($project_ID,$assignee_id){
404            $data_rep = $this->project_tasks($project_ID);
405            $tasks = array();
406            foreach($data_rep as $task){
407                if( $task['assignee']['id'] == $assignee_id ){
408                    $tasks[]=$task;
409                }
410            }
411
412            return $tasks;
413    }
414
415
416    //donne les tache d'un projet donné
417    function project_tasks($project_ID){
418            curl_setopt($this->ch, CURLOPT_URL , $this->url_base."/projects/".$project_ID."/tasks");
419            $data_rep = json_decode(curl_exec($this->ch),true);
420            //var_dump($data_rep);
421            $tasks = array();
422            foreach($data_rep['data'] as $task){
423                $tasks[]=$this->task($task['id']);
424            }
425            return $tasks;
426    }
427
428    //donne les détails d'un tache donné
429    function task($task_ID){
430            curl_setopt($this->ch, CURLOPT_URL , $this->url_base."/tasks/".$task_ID);
431            $data_rep = json_decode(curl_exec($this->ch),true);
432            //var_dump($data_rep);
433            $task = array();
434            $task_elt = $data_rep['data'];
435            $task=array( 'id' => $task_elt['id'] , 'name' =>$task_elt['name'], 'tags' => $task_elt['tags'], 'due_date' => $task_elt['due_on'], 'assignee' => $task_elt['assignee'], 'desc' => $task_elt['notes']);
436            return $task;
437    }
438
439
440    //donne les commentaires d'une tache
441    function task_comments($task_ID){
442        curl_setopt($this->ch, CURLOPT_URL, $this->url_base."/tasks/".$task_ID."/stories");
443        $data_rep = json_decode(curl_exec($this->ch),true);
444        $comments = array();
445        foreach( $data_rep['data'] as $storie){
446            if($storie['type'] == 'comment'){
447                $comments[$storie['text']] = $storie['id'];
448            }
449        }
450        return $comments;
451    }
452
453    //fonction de comparaison de deux date dans un tableau de taches
454    static function compare_date($task1, $task2){
455        date_default_timezone_set("UTC");
456
457        if( $task1['due_date'] == "" ){
458            //si la date 1 n'existe pas
459            if( $task2['due_date'] == "" ){
460                //si la date 2 n'existe pas
461                return 0;
462            }
463            else{
464                //si la date 2 existe
465                return 1;
466            }
467        }
468        else{
469            //si la date 1 existe
470            if( $task2['due_date'] == "" ){
471                //si la date 2 n'existe pas
472                return -1;
473            }
474            else{
475                // les deux dates existent donc on les comparent vraiment
476                $date1 = strtotime($task1['due_date']);
477                $date2 = strtotime($task2['due_date']);
478                if( $date1<$date2){
479                    return -1;
480                }
481                elseif( $date1 == $date2){
482                    return 0;
483                }
484                else{
485                    return 1;
486                }
487            }
488        }
489    }
490
491    // trie un tableau de taches par leur deadline
492    function due_date_sort($tasks){
493        uasort($tasks,array('remote_plugin_asana_APILink','compare_date'));
494        return $tasks;
495    }
496
497    //permet de trouver l'id du projet dans le workspace selon le nom du projet
498    function project_find($projects,$project_target_name){
499        foreach( $projects as $project_name => $project_id ){
500            if( $project_name == $project_target_name){
501                return $project_id;
502            }
503        }
504        return 0;
505    }
506
507    function string_filter($string, $tasks){
508        $tasks_cp = array();
509        while( count($tasks) !=0 ){
510            $task = array_shift($tasks);
511            if(strstr($task['name'],$string) or strstr($task['desc'],$string)){
512                $tasks_cp[] = $task;
513            }
514        }
515        return $tasks_cp;
516    }
517
518    //filtre un tableau de tache selon un tag
519    function tag_filter($tag_name, $tasks){
520        $tasks_cp = array();
521        while( count($tasks) !=0 ){
522            $task = array_shift($tasks);
523            if($this->tags_compare($tag_name,$task) == 1){
524                $tasks_cp[] = $task;
525            }
526        }
527        return $tasks_cp;
528    }
529
530    //compare le tag d'une tache à un nom de tag
531    function tags_compare($tag_name,$task){
532        foreach( $task['tags'] as $tag ){
533            if( $tag['name'] == $tag_name ){
534                return 1;
535            }
536        }
537        return 0;
538    }
539
540}
541
542
543