diff --git a/dicos/25_schedule.xml b/dicos/25_schedule.xml index 2dc1095..fc07576 100644 --- a/dicos/25_schedule.xml +++ b/dicos/25_schedule.xml @@ -6,7 +6,8 @@ - + schedule-apps + schedule diff --git a/src/schedule-2.0/config/routes.yaml b/src/schedule-2.0/config/routes.yaml index 1833a6e..114088d 100644 --- a/src/schedule-2.0/config/routes.yaml +++ b/src/schedule-2.0/config/routes.yaml @@ -40,6 +40,7 @@ app_logoutcas: path: /logoutcas defaults: { _controller: App\Controller\SecurityController:logoutcas } + #== Crop ========================================================================================================= app_crop01: path: /user/crop01 @@ -350,4 +351,9 @@ app_customer_report: app_customer_planning: path: /customer/planning/{key} - defaults: { _controller: App\Controller\ReportController:planning, access: 'customer' } \ No newline at end of file + defaults: { _controller: App\Controller\ReportController:planning, access: 'customer' } + +#== API =========================================================================================================== +app_api: + path: /api/{key} + defaults: { _controller: App\Controller\ApiController:api } \ No newline at end of file diff --git a/src/schedule-2.0/config/services.yaml b/src/schedule-2.0/config/services.yaml index 7ab60c4..1ac6453 100644 --- a/src/schedule-2.0/config/services.yaml +++ b/src/schedule-2.0/config/services.yaml @@ -41,6 +41,10 @@ services: public: true class: App\Service\passwordEncoder + app.ics.service: + public: true + class: App\Service\icsService + app.upload.listener: public: true class: App\Service\uploadListener diff --git a/src/schedule-2.0/src/Controller/ApiController.php b/src/schedule-2.0/src/Controller/ApiController.php new file mode 100755 index 0000000..a4a30ef --- /dev/null +++ b/src/schedule-2.0/src/Controller/ApiController.php @@ -0,0 +1,52 @@ +getDoctrine()->getManager(); + + $user=$em->getRepository("App:User")->findBy(["apikey"=>$key]); + if(!$user) { + return new Response("Accès refusé", 403); + } + + $ics = new icsService(); + $ics->debug(false); + + $content=$ics->writeheader(); + + $events=$em->getRepository("App:Event")->findBy(["user"=>$user]); + foreach($events as $event) { + $task=$event->getTask(); + $project=$task->getProject(); + $customer=$project->getCustomer(); + + $ics->set( + [ + 'allday' => $event->getAllday(), + 'description' => $event->getDescription(), + 'dtstart' => $event->getStart()->format("Y-m-d H:i:s"), + 'dtend' => $event->getEnd()->format("Y-m-d H:i:s"), + 'summary' => $customer->getName()."-".$project->getName()."-".$task->getName(), + 'uid' => "schedule".$event->getId() + ] + ); + + $content.=$ics->writeevent(); + } + + $content.=$ics->writefooter(); + + return new Response($content); + } +} diff --git a/src/schedule-2.0/src/Form/UserType.php b/src/schedule-2.0/src/Form/UserType.php index 51dc34d..5264e4a 100644 --- a/src/schedule-2.0/src/Form/UserType.php +++ b/src/schedule-2.0/src/Form/UserType.php @@ -116,6 +116,13 @@ class UserType extends AbstractType ] ); + $builder->add('apikey', + TextType::class, [ + "label" =>"Clé Accès", + "required" => false + ] + ); + $builder->add('avatar',HiddenType::class, array("empty_data" => "noavatar.png")); } diff --git a/src/schedule-2.0/src/Service/icsService.php b/src/schedule-2.0/src/Service/icsService.php new file mode 100644 index 0000000..bcdfc14 --- /dev/null +++ b/src/schedule-2.0/src/Service/icsService.php @@ -0,0 +1,135 @@ +fgdebug=$fgdebug; + } + + public function set($key, $val = false) { + if (is_array($key)) { + foreach ($key as $k => $v) { + if($k=="allday"&&(is_null($v)||$v=="")) $v=0; + + if($k!="allday"&&(is_null($v)||$v=="")) unset( $this->properties[$k]); + else $this->set($k, $v); + } + } + else { + if (in_array($key, $this->available_properties)) { + if($key=="allday") + $this->properties[$key] = $this->sanitize_val($val, $key, false); + else + $this->properties[$key] = $this->sanitize_val($val, $key,$this->properties["allday"]); + } + } + } + + public function writeheader() { + // Build ICS properties - add header + $header = array( + 'BEGIN:VCALENDAR', + 'VERSION:2.0', + 'PRODID:-//hacksw/handcal//NONSGML v1.0//EN', + 'CALSCALE:GREGORIAN', + 'X-WR-TIMEZONE:Europe/Paris' + ); + + return $this->exportformat($header); + } + + public function writefooter() { + // Build ICS properties - add footer + $footer[] = 'END:VCALENDAR'; + + return $this->exportformat($footer); + } + + public function writeevent() { + $event[]='BEGIN:VEVENT'; + + // Build ICS properties - add header + $props = array(); + foreach($this->properties as $k => $v) { + if($k === 'url') + $props[strtoupper($k . ';VALUE=URI')] = $v; + elseif(($k=='dtstart'||$k=='dtend')&&$this->properties['allday']) + $props[strtoupper($k . ';VALUE=DATE')] = $v; + else + $props[strtoupper($k)] = $v; + } + + // Set some default values + $props['DTSTAMP'] = $this->format_timestamp('now'); + if(!isset($props['UID'])) $props['UID'] = uniqid(); + + // Append properties + foreach ($props as $k => $v) { + $event[] = "$k:$v"; + } + + // Build ICS properties - add footer + $event[] = 'END:VEVENT'; + + return $this->exportformat($event); + } + + private function sanitize_val($val, $key = false, $allday) { + switch($key) { + case 'dtstamp': + $val = $this->format_timestamp($val); + break; + + case 'dtend': + case 'dtstart': + if($allday) + $val = $this->format_daystamp($val); + else + $val = $this->format_timestamp($val); + break; + + default: + $val = $this->escape_string($val); + } + + return $val; + } + + private function format_daystamp($timestamp) { + $dt = new \DateTime($timestamp, new \DateTimeZone('Europe/Paris')); + return $dt->format(self::DT_FORMATDAY); + } + + private function format_timestamp($timestamp) { + $dt = new \DateTime($timestamp, new \DateTimeZone('Europe/Paris')); + return $dt->format(self::DT_FORMAT); + } + + private function escape_string($str) { + return preg_replace('/([\,;])/','\\\$1', $str); + } + + private function exportformat($string) { + return implode(($this->fgdebug?"
":"\r\n"), $string).($this->fgdebug?"
":"\r\n"); + } +}