merge changes
This commit is contained in:
commit
5a99cdcc3b
457 changed files with 63199 additions and 38634 deletions
|
@ -12,6 +12,7 @@ namespace Hackspace\Bundle\CalciferBundle\Command;
|
|||
use Doctrine\ORM\EntityManager;
|
||||
use Hackspace\Bundle\CalciferBundle\Entity\Event;
|
||||
use Hackspace\Bundle\CalciferBundle\Entity\RepeatingEvent;
|
||||
use Hackspace\Bundle\CalciferBundle\Entity\RepeatingEventLogEntry;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
@ -52,7 +53,6 @@ class GenerateEventsCommand extends ContainerAwareCommand
|
|||
$event = null;
|
||||
while (($next_date = $parser->getNext()) < $end) {
|
||||
/** @var \DateTime $next_date */
|
||||
$output->writeln(sprintf("Creating Event %s for %s",$entity->summary,$next_date->format('Y-m-d H:i')));
|
||||
$event = new Event();
|
||||
$event->location = $entity->location;
|
||||
$event->startdate = $next_date;
|
||||
|
@ -75,6 +75,12 @@ class GenerateEventsCommand extends ContainerAwareCommand
|
|||
$event->addTag($tag);
|
||||
}
|
||||
$entityManager->persist($event);
|
||||
$logEntry = new RepeatingEventLogEntry();
|
||||
$logEntry->event = $event;
|
||||
$logEntry->repeating_event = $entity;
|
||||
$logEntry->event_startdate = $event->startdate;
|
||||
$logEntry->event_enddate = $event->enddate;
|
||||
$entityManager->persist($logEntry);
|
||||
$entityManager->flush();
|
||||
$parser->setNow($next_date);
|
||||
}
|
||||
|
|
|
@ -15,19 +15,8 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
|||
use Hackspace\Bundle\CalciferBundle\Entity\Event;
|
||||
use Hackspace\Bundle\CalciferBundle\Form\EventType;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Jsvrcek\ICS\Model\Calendar;
|
||||
use Jsvrcek\ICS\Utility\Formatter;
|
||||
use Jsvrcek\ICS\CalendarStream;
|
||||
use Jsvrcek\ICS\CalendarExport;
|
||||
use
|
||||
Sabre\VObject,
|
||||
Sabre\CalDAV,
|
||||
Sabre\DAV,
|
||||
Sabre\DAVACL,
|
||||
Sabre\DAV\Exception\Forbidden,
|
||||
Hackspace\Bundle\CalciferBundle\libs\CalciferCaldavBackend,
|
||||
Hackspace\Bundle\CalciferBundle\libs\CalciferPrincipalBackend;
|
||||
|
||||
use Sabre\VObject;
|
||||
/**
|
||||
* Event controller.
|
||||
*
|
||||
|
@ -35,45 +24,6 @@ use
|
|||
*/
|
||||
class EventController extends Controller
|
||||
{
|
||||
/**
|
||||
* Finds and displays a Event entity.
|
||||
*
|
||||
* @Route("/{url}", name="events_caldav", requirements={"url" : "caldav(.+)"})
|
||||
*/
|
||||
public function caldavEntry()
|
||||
{
|
||||
// Backends
|
||||
$calendarBackend = new CalciferCaldavBackend($this);
|
||||
$principalBackend = new CalciferPrincipalBackend();
|
||||
// Directory structure
|
||||
$tree = [
|
||||
new CalDAV\CalendarRootNode($principalBackend, $calendarBackend),
|
||||
];
|
||||
|
||||
$server = new DAV\Server($tree);
|
||||
|
||||
$server->setBaseUri('/caldav');
|
||||
|
||||
/*$aclPlugin = new DAVACL\Plugin();
|
||||
$aclPlugin->allowAccessToNodesWithoutACL = false;
|
||||
$server->addPlugin($aclPlugin);*/
|
||||
|
||||
/* CalDAV support */
|
||||
$caldavPlugin = new CalDAV\Plugin();
|
||||
$server->addPlugin($caldavPlugin);
|
||||
|
||||
/* WebDAV-Sync plugin */
|
||||
$server->addPlugin(new DAV\Sync\Plugin());
|
||||
|
||||
// Support for html frontend
|
||||
$browser = new DAV\Browser\Plugin();
|
||||
$server->addPlugin($browser);
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
||||
return new Response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all Event entities as ICS.
|
||||
*
|
||||
|
@ -96,22 +46,14 @@ class EventController extends Controller
|
|||
->setParameter('startdate', $now);
|
||||
$entities = $qb->getQuery()->execute();
|
||||
|
||||
$calendar = new Calendar();
|
||||
$calendar->setProdId('-//My Company//Cool Calendar App//EN');
|
||||
$vcalendar = new VObject\Component\VCalendar();
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
/** @var Event $entity */
|
||||
$event = $entity->ConvertToCalendarEvent();
|
||||
$calendar->addEvent($event);
|
||||
/** @var Event $entity */
|
||||
$vcalendar->add('VEVENT',$entity->ConvertToCalendarEvent());
|
||||
}
|
||||
|
||||
$calendarExport = new CalendarExport(new CalendarStream, new Formatter());
|
||||
$calendarExport->addCalendar($calendar);
|
||||
|
||||
//output .ics formatted text
|
||||
$result = $calendarExport->getStream();
|
||||
|
||||
$response = new Response($result);
|
||||
$response = new Response($vcalendar->serialize());
|
||||
$response->headers->set('Content-Type', 'text/calendar');
|
||||
|
||||
return $response;
|
||||
|
|
|
@ -16,12 +16,9 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
|||
use Hackspace\Bundle\CalciferBundle\Entity\Event;
|
||||
use Hackspace\Bundle\CalciferBundle\Form\EventType;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Jsvrcek\ICS\Model\Calendar;
|
||||
use Jsvrcek\ICS\Utility\Formatter;
|
||||
use Jsvrcek\ICS\CalendarStream;
|
||||
use Jsvrcek\ICS\CalendarExport;
|
||||
use Symfony\Component\HttpFoundation\AcceptHeader;
|
||||
|
||||
use Sabre\VObject;
|
||||
/**
|
||||
* Location controller.
|
||||
*
|
||||
|
@ -68,24 +65,15 @@ class LocationController extends Controller
|
|||
$entities = $qb->getQuery()->execute();
|
||||
|
||||
if ($format == 'ics') {
|
||||
$calendar = new Calendar();
|
||||
$calendar->setProdId('-//My Company//Cool Calendar App//EN');
|
||||
$vcalendar = new VObject\Component\VCalendar();
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
/** @var Event $entity */
|
||||
$event = $entity->ConvertToCalendarEvent();
|
||||
$calendar->addEvent($event);
|
||||
/** @var Event $entity */
|
||||
$vcalendar->add('VEVENT',$entity->ConvertToCalendarEvent());
|
||||
}
|
||||
|
||||
$calendarExport = new CalendarExport(new CalendarStream, new Formatter());
|
||||
$calendarExport->addCalendar($calendar);
|
||||
|
||||
//output .ics formatted text
|
||||
$result = $calendarExport->getStream();
|
||||
|
||||
$response = new Response($result);
|
||||
$response = new Response($vcalendar->serialize());
|
||||
$response->headers->set('Content-Type', 'text/calendar');
|
||||
|
||||
return $response;
|
||||
} else {
|
||||
return array(
|
||||
|
@ -213,8 +201,13 @@ class LocationController extends Controller
|
|||
);
|
||||
}
|
||||
|
||||
$retval = [
|
||||
"success" => true,
|
||||
"results" => $locations,
|
||||
];
|
||||
|
||||
$response = new Response(json_encode($locations));
|
||||
|
||||
$response = new Response(json_encode($retval));
|
||||
$response->headers->set('Content-Type', 'application/json');
|
||||
|
||||
return $response;
|
||||
|
|
|
@ -48,6 +48,28 @@ class RepeatingEventController extends Controller
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays all repeating events
|
||||
*
|
||||
* @Route("/logs", name="repeating_event_logs")
|
||||
* @Method("GET")
|
||||
* @Template()
|
||||
*/
|
||||
public function logIndexAction()
|
||||
{
|
||||
/** @var EntityManager $em */
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
/** @var EntityRepository $repo */
|
||||
$repo = $em->getRepository('CalciferBundle:RepeatingEventLogEntry');
|
||||
|
||||
$entities = $repo->findBy([], ['event_startdate' => 'DESC']);
|
||||
|
||||
return [
|
||||
'entities' => $entities,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a form to create a repeating event
|
||||
*
|
||||
|
|
|
@ -7,7 +7,6 @@ use Doctrine\ORM\EntityRepository;
|
|||
use Doctrine\ORM\QueryBuilder;
|
||||
use Hackspace\Bundle\CalciferBundle\Entity\Location;
|
||||
use Hackspace\Bundle\CalciferBundle\Entity\Tag;
|
||||
use Jsvrcek\ICS\Model\Description\Geo;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
|
@ -16,18 +15,12 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
|||
use Hackspace\Bundle\CalciferBundle\Entity\Event;
|
||||
use Hackspace\Bundle\CalciferBundle\Form\EventType;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Jsvrcek\ICS\Model\Calendar;
|
||||
use Jsvrcek\ICS\Model\CalendarEvent;
|
||||
use Jsvrcek\ICS\Model\Relationship\Attendee;
|
||||
use Jsvrcek\ICS\Model\Relationship\Organizer;
|
||||
|
||||
use Jsvrcek\ICS\Utility\Formatter;
|
||||
use Jsvrcek\ICS\CalendarStream;
|
||||
use Jsvrcek\ICS\CalendarExport;
|
||||
use Symfony\Component\Validator\Constraints\DateTime;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Symfony\Component\HttpFoundation\AcceptHeader;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* Tag controller.
|
||||
*
|
||||
|
@ -143,23 +136,14 @@ EOF;
|
|||
}
|
||||
|
||||
if ($format == 'ics') {
|
||||
$calendar = new Calendar();
|
||||
$calendar->setProdId('-//My Company//Cool Calendar App//EN');
|
||||
$calendar->setTimeZone(new \DateTimeZone('Europe/Berlin'));
|
||||
$vcalendar = new VObject\Component\VCalendar();
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
/** @var Event $entity */
|
||||
$event = $entity->ConvertToCalendarEvent();
|
||||
$calendar->addEvent($event);
|
||||
/** @var Event $entity */
|
||||
$vcalendar->add('VEVENT',$entity->ConvertToCalendarEvent());
|
||||
}
|
||||
|
||||
$calendarExport = new CalendarExport(new CalendarStream, new Formatter());
|
||||
$calendarExport->addCalendar($calendar);
|
||||
|
||||
//output .ics formatted text
|
||||
$result = $calendarExport->getStream();
|
||||
|
||||
$response = new Response($result);
|
||||
$response = new Response($vcalendar->serialize());
|
||||
$response->headers->set('Content-Type', 'text/calendar');
|
||||
|
||||
return $response;
|
||||
|
@ -202,8 +186,13 @@ EOF;
|
|||
];
|
||||
}
|
||||
|
||||
$retval = [
|
||||
'success' => true,
|
||||
'results' => $tags,
|
||||
];
|
||||
|
||||
$response = new Response(json_encode($tags));
|
||||
|
||||
$response = new Response(json_encode($retval));
|
||||
$response->headers->set('Content-Type', 'application/json');
|
||||
|
||||
return $response;
|
||||
|
|
|
@ -5,17 +5,7 @@ namespace Hackspace\Bundle\CalciferBundle\Entity;
|
|||
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Jsvrcek\ICS\Model\Description\Location As EventLocation;
|
||||
use Symfony\Component\Validator\Constraints\DateTime;
|
||||
use Jsvrcek\ICS\Model\Calendar;
|
||||
use Jsvrcek\ICS\Model\CalendarEvent;
|
||||
use Jsvrcek\ICS\Model\Relationship\Attendee;
|
||||
use Jsvrcek\ICS\Model\Relationship\Organizer;
|
||||
|
||||
use Jsvrcek\ICS\Utility\Formatter;
|
||||
use Jsvrcek\ICS\CalendarStream;
|
||||
use Jsvrcek\ICS\CalendarExport;
|
||||
use Jsvrcek\ICS\Model\Description\Geo;
|
||||
|
||||
/**
|
||||
* Event
|
||||
|
@ -144,32 +134,41 @@ class Event extends BaseEntity
|
|||
|
||||
|
||||
public function ConvertToCalendarEvent() {
|
||||
$event = new CalendarEvent();
|
||||
$event->setStart($this->startdate);
|
||||
if ($this->enddate instanceof \DateTime)
|
||||
$event->setEnd($this->enddate);
|
||||
$event->setSummary($this->summary);
|
||||
$event->setUrl($this->url);
|
||||
$uid = sprintf("https://%s/termine/%s",$_SERVER['HTTP_HOST'],$this->slug);
|
||||
$event->setUid($uid);
|
||||
if (count($this->tags) > 0) {
|
||||
$categories = [];
|
||||
foreach($this->tags as $tag) {
|
||||
$event->addCategory($tag->name);
|
||||
}
|
||||
$categories = [];
|
||||
foreach($this->tags as $tag) {
|
||||
$categories[] = $tag->name;
|
||||
}
|
||||
|
||||
if (array_key_exists('HTTP_HOST',$_SERVER)) {
|
||||
$uid = sprintf("https://%s/termine/%s",$_SERVER['HTTP_HOST'],$this->slug);
|
||||
} else {
|
||||
$uid = sprintf("https://localhost/termine/%s",$this->slug);
|
||||
}
|
||||
|
||||
$event = [
|
||||
'SUMMARY' => $this->summary,
|
||||
'DTSTART' => $this->startdate,
|
||||
'DESCRIPTION' => $this->description,
|
||||
'URL' => $this->url,
|
||||
'CATEGORIES' => $categories,
|
||||
'UID' => $uid,
|
||||
];
|
||||
if (!is_null($this->enddate))
|
||||
$event["DTEND"] = $this->enddate;
|
||||
|
||||
if ($this->location instanceof Location) {
|
||||
$location = new EventLocation();
|
||||
$location->setName($this->location->name);
|
||||
$event->setLocations([$location]);
|
||||
$event["LOCATION"] = $this->location->name;
|
||||
if (\is_float($this->location->lon) && \is_float($this->location->lat)) {
|
||||
$geo = new Geo();
|
||||
$geo->setLatitude($this->location->lat);
|
||||
$geo->setLongitude($this->location->lon);
|
||||
$event->setGeo($geo);
|
||||
$event["GEO"] = [$this->location->lat, $this->location->lon];
|
||||
}
|
||||
}
|
||||
$event->setDescription($this->description);
|
||||
if (!array_key_exists('HTTP_HOST',$_SERVER)) {
|
||||
$dtstamp = new \DateTime();
|
||||
$dtstamp->setDate(2016,06,27);
|
||||
$dtstamp->setTime(0,0,0);
|
||||
$event['DTSTAMP'] = $dtstamp;
|
||||
}
|
||||
|
||||
return $event;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: tim
|
||||
* Date: 21.11.2016
|
||||
* Time: 21:15
|
||||
*/
|
||||
|
||||
namespace Hackspace\Bundle\CalciferBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Class RepeatingEventLogEntry
|
||||
* @package Hackspace\Bundle\CalciferBundle\Entity
|
||||
*
|
||||
* @property RepeatingEvent $repeating_event
|
||||
* @property Event $event
|
||||
* @property \DateTime $event_startdate
|
||||
* @property \DateTime $event_enddate
|
||||
*
|
||||
* @ORM\Table(name="repeating_events_log_entries")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class RepeatingEventLogEntry extends BaseEntity
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*
|
||||
* @ORM\Column(name="repeating_events_id", type="integer", nullable=false)
|
||||
*/
|
||||
protected $repeating_events_id;
|
||||
|
||||
/**
|
||||
* @var RepeatingEvent
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="RepeatingEvent")
|
||||
* @ORM\JoinColumn(name="repeating_events_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $repeating_event;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="events_id", type="integer", nullable=false)
|
||||
*/
|
||||
protected $events_id;
|
||||
|
||||
/**
|
||||
* @var Event
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="Event")
|
||||
* @ORM\JoinColumn(name="events_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $event;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*
|
||||
* @ORM\Column(name="event_startdate", type="datetimetz")
|
||||
*/
|
||||
protected $event_startdate;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*
|
||||
* @ORM\Column(name="event_enddate", type="datetimetz", nullable=true)
|
||||
*/
|
||||
protected $event_enddate;
|
||||
}
|
|
@ -55,7 +55,7 @@ trait TagTrait
|
|||
}
|
||||
return implode(',', $tags);
|
||||
} else {
|
||||
return '';
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,34 @@
|
|||
height: auto;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
#event_location.ui.dropdown.active {
|
||||
.text .ui.fluid.card {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
#event_location.ui.dropdown {
|
||||
input.search {
|
||||
height: 100%;
|
||||
line-height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.default.text {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.text {
|
||||
width: 100%;
|
||||
|
||||
.ui.fluid.card {
|
||||
.description {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#view-map, #map {
|
||||
|
|
|
@ -13,6 +13,12 @@ jQuery(document).ready(function () {
|
|||
jQuery('.icon.link').popup();
|
||||
}
|
||||
|
||||
$('.ui.sticky')
|
||||
.sticky({
|
||||
context: '#main'
|
||||
})
|
||||
;
|
||||
|
||||
if (jQuery('input[type=datetime]').length > 0) {
|
||||
jQuery('input[type=datetime]').datetimepicker({lang: 'de', format: 'Y-m-d H:i'});
|
||||
}
|
||||
|
@ -109,85 +115,71 @@ $(document).ready(function() {
|
|||
if (card_selector.length > 0) {
|
||||
calcBoxSize(4);
|
||||
}
|
||||
|
||||
$location = $('#event_location');
|
||||
|
||||
$('#event_tags').selectize({
|
||||
create: true,
|
||||
diacritics: true,
|
||||
valueField: 'name',
|
||||
labelField: 'name',
|
||||
searchField: 'name',
|
||||
render: {
|
||||
item: function(data,escape){
|
||||
console.log([data,escape]);
|
||||
return '<div class="ui green compact small label"><i class="tag icon"></i>' + escape(data.name) + '</div>';
|
||||
}
|
||||
},
|
||||
load: function(query, callback) {
|
||||
if (!query.length) return callback();
|
||||
$.ajax({
|
||||
url: "/tags/",
|
||||
type: "GET",
|
||||
dataType: 'json',
|
||||
data: {
|
||||
q: query
|
||||
if ($location.length == 1) {
|
||||
$('#event_location')
|
||||
.dropdown({
|
||||
minCharacters: 4,
|
||||
allowAdditions: true,
|
||||
apiSettings: {
|
||||
url: '/orte/?q={query}'
|
||||
},
|
||||
error: function() {
|
||||
callback();
|
||||
fields: {
|
||||
remoteValues : 'results', // grouping for api results
|
||||
values : 'values', // grouping for all dropdown values
|
||||
name : 'name', // displayed dropdown text
|
||||
value : 'name' // actual dropdown value
|
||||
},
|
||||
success: function(res) {
|
||||
console.log(res);
|
||||
callback(res);
|
||||
templates: {
|
||||
menu: function(response, fields) {
|
||||
var
|
||||
values = response[fields.values] || {},
|
||||
html = ''
|
||||
;
|
||||
$.each(values, function(index, option) {
|
||||
var item = option;
|
||||
html += '<div class="item" data-value="' + option[fields.value] + '"><div class="ui fluid green card">' +
|
||||
'<div class="content">'+
|
||||
'<div class="header">' +
|
||||
'<i class="ui icon map marker"></i>' + item.name +
|
||||
'</div>' +
|
||||
'<div class="meta">'+
|
||||
(item.lon && item.lat ? 'lon: '+ escape(item.lon)+' lat: ' + escape(item.lat) : '')+
|
||||
(item.streetaddress ? ' Anschrift: ' + item.streetaddress + ' ' + item.streetnumber + ' ' + item.zipcode + ' ' + item.city : '')+
|
||||
'</div>'+
|
||||
(item.description ? '<div class="description">' + item.description + '</div>' : '') +
|
||||
'</div>'+
|
||||
'</div></div>';
|
||||
});
|
||||
return html;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
$('#event_location').selectize({
|
||||
create: true,
|
||||
diacritics: true,
|
||||
valueField: 'name',
|
||||
labelField: 'name',
|
||||
searchField: 'name',
|
||||
maxItems: 1,
|
||||
render: {
|
||||
item: function(data,escape){
|
||||
console.log([data,escape]);
|
||||
return '<div class="ui green compact small label"><i class="map marker icon"></i>' + escape(data.name) + '</div>';
|
||||
},
|
||||
option: function(item, escape) {
|
||||
return '<div class="ui fluid green card">' +
|
||||
'<div class="content">'+
|
||||
'<div class="header">' +
|
||||
'<i class="ui icon map marker"></i>' + escape(item.name) +
|
||||
'</div>' +
|
||||
'<div class="meta">'+
|
||||
(item.lon && item.lat ? 'lon: '+ escape(item.lon)+' lat: ' + escape(item.lat) : '')+
|
||||
(item.streetaddress ? ' Anschrift: ' + item.streetaddress + ' ' + item.streetnumber + ' ' + item.zipcode + ' ' + item.city : '')+
|
||||
'</div>'+
|
||||
(item.description ? '<div class="description">' + item.description + '</div>' : '') +
|
||||
'</div>'+
|
||||
'</div>';
|
||||
$('#event_tags')
|
||||
.dropdown({
|
||||
minCharacters: 2,
|
||||
allowAdditions: true,
|
||||
apiSettings: {
|
||||
url: '/tags/?q={query}'
|
||||
},
|
||||
fields: {
|
||||
remoteValues: 'results', // grouping for api results
|
||||
values: 'values', // grouping for all dropdown values
|
||||
name: 'name', // displayed dropdown text
|
||||
value: 'name' // actual dropdown value
|
||||
}/*,
|
||||
templates: {
|
||||
label: function (value, text) {
|
||||
return '<i class="tag icon"></i>' + text + '<i class="delete icon"></i>';
|
||||
}
|
||||
}*/
|
||||
}
|
||||
},
|
||||
load: function(query, callback) {
|
||||
if (!query.length) return callback();
|
||||
$.ajax({
|
||||
url: "/orte/",
|
||||
type: "GET",
|
||||
dataType: 'json',
|
||||
data: {
|
||||
q: query
|
||||
},
|
||||
error: function() {
|
||||
callback();
|
||||
},
|
||||
success: function(res) {
|
||||
console.log(res);
|
||||
callback(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
if (view_map_selector.length == 1) {
|
||||
jQuery('.show_map').click(addGeoCoordinates);
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
%}
|
||||
<link rel="stylesheet" href="{{ asset_url }}"/>
|
||||
{% endstylesheets %}
|
||||
<link rel="stylesheet" href="/vendor/selectize.js/dist/css/selectize.css"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
@ -19,7 +18,6 @@
|
|||
%}
|
||||
<script src="{{ asset_url }}"></script>
|
||||
{% endjavascripts %}
|
||||
<script src="/vendor/selectize.js/dist/js/standalone/selectize.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body -%}
|
||||
|
|
|
@ -80,16 +80,37 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="required field">
|
||||
<div class="field">
|
||||
<label for="event_location">Ort</label>
|
||||
|
||||
<div class="ui icon input attached-{% if entity.location.lat|default(0) > 0 %}geo-{% endif %}label">
|
||||
<input type="text"
|
||||
id="event_location"
|
||||
name="location"
|
||||
maxlength="255"
|
||||
value="{{ entity.location.name|default('') }}"
|
||||
class="form-control">
|
||||
<div id="event_location" class="ui fluid search selection dropdown">
|
||||
<input type="hidden" name="location">
|
||||
<div class="default text">
|
||||
{% if entity.location is null %}
|
||||
Wähle einen Ort…
|
||||
{% else %}
|
||||
<div class="ui fluid green card">
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<i class="ui icon map marker"></i> {{ entity.location.name }}
|
||||
</div>
|
||||
<div class="meta">
|
||||
{% if (not entity.location.lat is null) and (not entity.location.lon is null) %}
|
||||
lon: {{ entity.location.lon }}, lat: {{ entity.location.lat }}
|
||||
{% endif %}
|
||||
{% if (not entity.location.streetaddress) %}
|
||||
Anschrift: {{ entity.location.streetaddress }} {{ entity.location.streetnumber }} {{ entity.location.zipcode }} {{ entity.location.city }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="menu">
|
||||
</div>
|
||||
</input>
|
||||
</div>
|
||||
<input type="hidden" name="location_lat" value="{{ entity.location.lat|default('') }}">
|
||||
<input type="hidden" name="location_lon" value="{{ entity.location.lon|default('') }}">
|
||||
<i class="icon map marker"></i>
|
||||
|
@ -123,11 +144,17 @@
|
|||
<label for="event_tags">Tags</label>
|
||||
|
||||
<div class="ui icon input">
|
||||
<input type="text"
|
||||
id="event_tags"
|
||||
name="tags"
|
||||
value="{{ entity.getTagsAsText() }}"
|
||||
class="form-control">
|
||||
<div class="ui fluid search multiple selection dropdown" id="event_tags">
|
||||
<input name="tags" type="hidden" value="{{ entity.getTagsAsText()|default('') }}">
|
||||
|
||||
<div class="default text">Du kannst hier kommasepariert Tags angeben…</div>
|
||||
<div class="menu">
|
||||
{% for tag in entity.tags %}
|
||||
<div class="item" data-value="{{ tag.name }}">{{ tag.name }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</input>
|
||||
</div>
|
||||
<i class="icon tag"></i>
|
||||
</div>
|
||||
<div class="ui label">Du kannst hier kommasepariert <a
|
||||
|
@ -164,5 +191,5 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<input type="submit" class="ui button green" value="Speichern"/>
|
||||
<input type="submit" class="ui button green" name="save" value="Speichern"/>
|
||||
</form>
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
{% extends 'CalciferBundle::layout.html.twig' %}
|
||||
|
||||
{% block css %}
|
||||
{% stylesheets filter="compass"
|
||||
"@CalciferBundle/Resources/assets/css/events.scss" %}
|
||||
<link rel="stylesheet" href="{{ asset_url }}"/>
|
||||
{% endstylesheets %}
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% javascripts
|
||||
"@CalciferBundle/Resources/assets/js/events.js" %}
|
||||
<script src="{{ asset_url }}"></script>
|
||||
{% endjavascripts %}
|
||||
{% endblock %}
|
||||
|
||||
{% block body -%}
|
||||
<div class="ui basic segment">
|
||||
<h1 class="ui green block dividing header">
|
||||
Logeinträge für Wiederholende Termine
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="ui basic segment">
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Wiederholender Termin</th>
|
||||
<th>Termin</th>
|
||||
<th>Termin Startdatum</th>
|
||||
<th>Termin Enddatum</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entity in entities %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ entity.repeating_event.summary }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ path('_show', {'slug':entity.event.slug}) }}">{{ entity.event.summary }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ entity.event_startdate.format('Y-m-d H:i') }}
|
||||
</td>
|
||||
<td>
|
||||
{% if entity.event_enddate %}
|
||||
{{ entity.event_enddate.format('Y-m-d H:i') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -26,8 +26,8 @@
|
|||
<p>Es gibt 2 verschiedene Wiederholungsmustertypen. Feste Termine oder Interval Termine.</p>
|
||||
|
||||
<p>Der erste definiert sich dadurch das der Termin immer an einem bestimmten Tag im Monat passieren soll.
|
||||
Das Hackspace-Plenum findet z.B. am „<code>Zweiten Freitag des Monats</code>“ statt. Die
|
||||
Sicherheitssprechstunde findet immer am „<code>Ersten Dienstag des Monats</code>“ statt. Anhand dieser
|
||||
Das Hackspace-Plenum findet z.B. am „<code>Zweiter Freitag des Monats</code>“ statt. Die
|
||||
Sicherheitssprechstunde findet immer am „<code>Erster Dienstag des Monats</code>“ statt. Anhand dieser
|
||||
Beispiele sollte eigentlich klar sein wie dieses Wiederholungsmuster funktioniert:</p>
|
||||
|
||||
<p>An erster stelle definiert man die Woche: Erster, Zweiter, Dritter, Letzter (In manchen Fällen kann
|
||||
|
@ -42,4 +42,4 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<link href="/semantic/dist/semantic.css" rel="stylesheet">
|
||||
{% stylesheets filter="compass"
|
||||
"@CalciferBundle/Resources/assets/css/main.scss"
|
||||
"css/custom.scss"
|
||||
%}
|
||||
<link rel="stylesheet" href="{{ asset_url }}"/>
|
||||
{% endstylesheets %}
|
||||
|
@ -19,15 +18,15 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
{% include "CalciferBundle::navigation.html.twig" %}
|
||||
<div class="ui sticky">
|
||||
{% include "CalciferBundle::navigation.html.twig" %}
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
{% block body %}{% endblock %}
|
||||
</div>
|
||||
<!-- jQuery (necessary for Bootstraps JavaScript plugins) -->
|
||||
<script src="{{ asset('js/jquery.js') }}"></script>
|
||||
<!-- Include all JavaScripts, compiled by Assetic -->
|
||||
<script src="{{ asset('semantic/dist/semantic.min.js') }}"></script>
|
||||
{% block javascripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<header class="ui fixed green main menu">
|
||||
<div class="ui basic segment">
|
||||
<div class="title {% if app.request.pathinfo == path('') %}active {% endif %}item"><a href="{{ path('') }}">Start</a></div>
|
||||
<div class="{% if app.request.pathinfo == path('_new') %}active {% endif %}item"><a href="{{ path('_new') }}">Neuer Termin</a></div>
|
||||
<div class="{% if app.request.pathinfo == path('repeating_event_show') %}active {% endif %}item"><a href="{{ path('repeating_event_show') }}">Wiederholende Termine</a></div>
|
||||
<div class="{% if app.request.pathinfo == path('about_calcifer') %}active {% endif %}item"><a href="{{ path('about_calcifer') }}">Über Calcifer</a></div>
|
||||
</div>
|
||||
</header>
|
||||
<header class="ui green main menu">
|
||||
<a class="title {% if app.request.pathinfo == path('') %}active {% endif %}item" href="{{ path('') }}">Start</a>
|
||||
<a class="{% if app.request.pathinfo == path('_new') %}active {% endif %}item" href="{{ path('_new') }}">Neuer Termin</a>
|
||||
<a class="{% if app.request.pathinfo == path('repeating_event_show') %}active {% endif %}item" href="{{ path('repeating_event_show') }}">Wiederholende Termine</a>
|
||||
<a class="{% if app.request.pathinfo == path('about_calcifer') %}active {% endif %}item" href="{{ path('about_calcifer') }}">Über Calcifer</a>
|
||||
</header>
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Hackspace\Bundle\CalciferBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class DefaultControllerTest extends WebTestCase
|
||||
{
|
||||
public function testIndex()
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$crawler = $client->request('GET', '/hello/Fabien');
|
||||
|
||||
$this->assertTrue($crawler->filter('html:contains("Hello Fabien")')->count() > 0);
|
||||
}
|
||||
}
|
|
@ -2,54 +2,191 @@
|
|||
|
||||
namespace Hackspace\Bundle\CalciferBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Doctrine\Bundle\DoctrineBundle\Registry;
|
||||
use Doctrine\ORM\Decorator\EntityManagerDecorator;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Hackspace\Bundle\CalciferBundle\Entity\Event;
|
||||
use Liip\FunctionalTestBundle\Test\WebTestCase;
|
||||
|
||||
class EventControllerTest extends WebTestCase
|
||||
{
|
||||
/*
|
||||
public function testCompleteScenario()
|
||||
/** @var \DateTime */
|
||||
private $now = null;
|
||||
|
||||
/** @var \DateTime */
|
||||
private $startdate = null;
|
||||
|
||||
/** @var \DateTime */
|
||||
private $enddate = null;
|
||||
|
||||
const dateformat = "Y-m-d H:i";
|
||||
|
||||
/**
|
||||
* EventControllerTest constructor.
|
||||
*/
|
||||
public function __construct($name = null, array $data = [], $dataName = '')
|
||||
{
|
||||
// Create a new client to browse the application
|
||||
$client = static::createClient();
|
||||
parent::__construct($name,$data,$dataName);
|
||||
$this->now = new \DateTime();
|
||||
$this->now->setTime(0,0,0);
|
||||
|
||||
// Create a new entry in the database
|
||||
$crawler = $client->request('GET', '//');
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode(), "Unexpected HTTP status code for GET //");
|
||||
$crawler = $client->click($crawler->selectLink('Create a new entry')->link());
|
||||
$tz = new \DateTimeZone("Europe/Berlin");
|
||||
$this->now->setTimezone($tz);
|
||||
|
||||
// Fill in the form and submit it
|
||||
$form = $crawler->selectButton('Create')->form(array(
|
||||
'hackspace_bundle_calciferbundle_event[field_name]' => 'Test',
|
||||
// ... other fields to fill
|
||||
));
|
||||
$this->startdate = clone $this->now;
|
||||
$this->startdate->add(new \DateInterval("P1D"));
|
||||
$this->enddate = clone $this->now;
|
||||
$this->enddate->add(new \DateInterval("P1DT2H"));
|
||||
|
||||
$client->submit($form);
|
||||
$crawler = $client->followRedirect();
|
||||
|
||||
// Check data in the show view
|
||||
$this->assertGreaterThan(0, $crawler->filter('td:contains("Test")')->count(), 'Missing element td:contains("Test")');
|
||||
|
||||
// Edit the entity
|
||||
$crawler = $client->click($crawler->selectLink('Edit')->link());
|
||||
|
||||
$form = $crawler->selectButton('Update')->form(array(
|
||||
'hackspace_bundle_calciferbundle_event[field_name]' => 'Foo',
|
||||
// ... other fields to fill
|
||||
));
|
||||
|
||||
$client->submit($form);
|
||||
$crawler = $client->followRedirect();
|
||||
|
||||
// Check the element contains an attribute with value equals "Foo"
|
||||
$this->assertGreaterThan(0, $crawler->filter('[value="Foo"]')->count(), 'Missing element [value="Foo"]');
|
||||
|
||||
// Delete the entity
|
||||
$client->submit($crawler->selectButton('Delete')->form());
|
||||
$crawler = $client->followRedirect();
|
||||
|
||||
// Check the entity has been delete on the list
|
||||
$this->assertNotRegExp('/Foo/', $client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
*/
|
||||
public static function runCommandStatic($name) {
|
||||
$command = sprintf("php app/console %s", $name);
|
||||
$output = "";
|
||||
exec($command,$output);
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
EventControllerTest::runCommandStatic("doctrine:database:drop --force --env=test");
|
||||
EventControllerTest::runCommandStatic("doctrine:database:create --env=test");
|
||||
EventControllerTest::runCommandStatic("doctrine:schema:create --env=test");
|
||||
}
|
||||
|
||||
|
||||
public function testEmptyListing() {
|
||||
$client = static::makeClient();
|
||||
$crawler = $client->request('GET', '/');
|
||||
$this->assertStatusCode(200, $client);
|
||||
}
|
||||
|
||||
public function testPostEventForm()
|
||||
{
|
||||
$client = static::makeClient();
|
||||
|
||||
$url = $client->getContainer()->get('router')->generate('_new');
|
||||
|
||||
$crawler = $client->request('GET', $url);
|
||||
$this->assertStatusCode(200, $client);
|
||||
|
||||
$form = $crawler->selectButton('save')->form();
|
||||
|
||||
|
||||
|
||||
|
||||
$form['startdate'] = $this->startdate->format(EventControllerTest::dateformat);
|
||||
$form['enddate'] = $this->enddate->format(EventControllerTest::dateformat);
|
||||
$form['summary'] = "Testevent";
|
||||
$form['url'] = "https://calcifer.datenknoten.me";
|
||||
$form["location"] = "Krautspace";
|
||||
$form["location_lat"] = 1;
|
||||
$form["location_lon"] = 2;
|
||||
$form["tags"] = "foo,bar,krautspace";
|
||||
$form["description"] = "Testdescription";
|
||||
|
||||
$crawler = $client->submit($form);
|
||||
|
||||
$this->assertStatusCode(302, $client);
|
||||
|
||||
$target = $client->getResponse()->headers->get('location');
|
||||
|
||||
$slug = explode("/",$target)[2];
|
||||
|
||||
$this->assertGreaterThan(0,strlen($slug));
|
||||
|
||||
/** @var EntityManagerDecorator $em */
|
||||
$em = $this->getContainer()->get('doctrine')->getManager();
|
||||
|
||||
/** @var EntityRepository $repo */
|
||||
$repo = $em->getRepository('CalciferBundle:Event');
|
||||
|
||||
$qb = $em->createQueryBuilder();
|
||||
$qb->select(array('e'))
|
||||
->from('CalciferBundle:Event', 'e')
|
||||
->innerJoin('e.tags','t')
|
||||
->innerJoin('e.location','l')
|
||||
->where('e.slug>= :slug')
|
||||
->setParameter('slug', $slug);
|
||||
$entities = $qb->getQuery()->execute();
|
||||
|
||||
$this->assertCount(1,$entities);
|
||||
|
||||
/** @var Event $entity */
|
||||
$entity = $entities[0];
|
||||
|
||||
$this->assertInstanceOf('Hackspace\Bundle\CalciferBundle\Entity\Event', $entity);
|
||||
|
||||
$this->assertTrue($this->startdate == $entity->startdate, "Startdate equal");
|
||||
$this->assertTrue($this->enddate == $entity->enddate, "Enddate equal");
|
||||
$this->assertTrue($form["summary"]->getValue() == $entity->summary, "Summary equal");
|
||||
$this->assertTrue($form["url"]->getValue() == $entity->url, "URL equal");
|
||||
$this->assertTrue($form["description"]->getValue() == $entity->description, "Description equal");
|
||||
|
||||
$tags = explode(",",$form["tags"]->getValue());
|
||||
foreach($entity->tags as $tag) {
|
||||
$this->assertTrue(in_array($tag->name,$tags));
|
||||
}
|
||||
|
||||
$this->assertTrue($form["location"]->getValue() == $entity->location->name);
|
||||
$this->assertTrue($form["location_lat"]->getValue() == $entity->location->lat);
|
||||
$this->assertTrue($form["location_lon"]->getValue() == $entity->location->lon);
|
||||
|
||||
$em->close();
|
||||
|
||||
/** @var Registry $doc */
|
||||
$doc = $this->getContainer()->get('doctrine');
|
||||
|
||||
foreach($doc->getConnections() as $connection) {
|
||||
$connection->close();
|
||||
}
|
||||
}
|
||||
|
||||
public function testICS() {
|
||||
|
||||
$client = static::makeClient();
|
||||
|
||||
// events_ics
|
||||
|
||||
$url = $client->getContainer()->get('router')->generate('events_ics');
|
||||
|
||||
$crawler = $client->request('GET', $url);
|
||||
$this->assertStatusCode(200, $client);
|
||||
|
||||
$test_doc = <<<EOF
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//Sabre//Sabre VObject 4.1.1//EN
|
||||
CALSCALE:GREGORIAN
|
||||
BEGIN:VEVENT
|
||||
UID:https://localhost/termine/testevent
|
||||
DTSTAMP;TZID=Europe/Berlin:20160627T000000
|
||||
SUMMARY:Testevent
|
||||
DTSTART:%s
|
||||
DESCRIPTION:Testdescription
|
||||
URL;VALUE=URI:https://calcifer.datenknoten.me
|
||||
CATEGORIES:foo,bar,krautspace
|
||||
DTEND:%s
|
||||
LOCATION:Krautspace
|
||||
GEO:1;2
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
|
||||
EOF;
|
||||
$new_tz = new \DateTimeZone("UTC");
|
||||
$this->startdate->setTimezone($new_tz);
|
||||
$this->enddate->setTimezone($new_tz);
|
||||
$start = $this->startdate->format("Ymd") . "T" . $this->startdate->format("His") . "Z";
|
||||
$end = $this->enddate->format("Ymd") . "T" . $this->enddate->format("His") . "Z";
|
||||
|
||||
$test_doc = sprintf($test_doc,$start,$end);
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
|
||||
$content = preg_replace('~\R~u', "\r\n", $content);
|
||||
$test_doc = preg_replace('~\R~u', "\r\n", $test_doc);
|
||||
|
||||
$this->assertGreaterThan(0,strlen($content));
|
||||
$this->assertEquals($test_doc, $content);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,312 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: tim
|
||||
* Date: 15.11.14
|
||||
* Time: 17:13
|
||||
*/
|
||||
|
||||
namespace Hackspace\Bundle\CalciferBundle\libs;
|
||||
|
||||
use Jsvrcek\ICS\Model\Calendar;
|
||||
use Jsvrcek\ICS\CalendarExport;
|
||||
use Jsvrcek\ICS\CalendarStream;
|
||||
use Jsvrcek\ICS\Model\CalendarEvent;
|
||||
use Jsvrcek\ICS\Utility\Formatter;
|
||||
use Sabre\CalDAV\Backend\AbstractBackend;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Hackspace\Bundle\CalciferBundle\Entity\Event;
|
||||
|
||||
class CalciferCaldavBackend extends AbstractBackend
|
||||
{
|
||||
/** @var Controller */
|
||||
private $controller = null;
|
||||
|
||||
function __construct(Controller $controller)
|
||||
{
|
||||
$this->controller = $controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of calendars for a principal.
|
||||
*
|
||||
* Every project is an array with the following keys:
|
||||
* * id, a unique id that will be used by other functions to modify the
|
||||
* calendar. This can be the same as the uri or a database key.
|
||||
* * uri, which the basename of the uri with which the calendar is
|
||||
* accessed.
|
||||
* * principaluri. The owner of the calendar. Almost always the same as
|
||||
* principalUri passed to this method.
|
||||
*
|
||||
* Furthermore it can contain webdav properties in clark notation. A very
|
||||
* common one is '{DAV:}displayname'.
|
||||
*
|
||||
* Many clients also require:
|
||||
* {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
|
||||
* For this property, you can just return an instance of
|
||||
* Sabre\CalDAV\Property\SupportedCalendarComponentSet.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri)
|
||||
{
|
||||
return [[
|
||||
'id' => 1,
|
||||
'uri' => 'calendar',
|
||||
'principaluri' => '/caldav/calcifer',
|
||||
]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar for a principal.
|
||||
*
|
||||
* If the creation was a success, an id must be returned that can be used to reference
|
||||
* this calendar in other methods, such as updateCalendar.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $calendarUri
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
public function createCalendar($principalUri, $calendarUri, array $properties)
|
||||
{
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId)
|
||||
{
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
|
||||
private function FormatCalendarEvent(CalendarEvent $event)
|
||||
{
|
||||
$stream = new CalendarStream();
|
||||
$formatter = new Formatter();
|
||||
$stream->addItem('BEGIN:VEVENT')
|
||||
->addItem('UID:' . $event->getUid())
|
||||
->addItem('DTSTART:' . $formatter->getFormattedUTCDateTime($event->getStart()))
|
||||
->addItem('DTEND:' . $formatter->getFormattedUTCDateTime($event->getEnd()))
|
||||
->addItem('SUMMARY:' . $event->getSummary())
|
||||
->addItem('DESCRIPTION:' . $event->getDescription());
|
||||
|
||||
if ($event->getClass())
|
||||
$stream->addItem('CLASS:' . $event->getClass());
|
||||
|
||||
/* @var $location Location */
|
||||
foreach ($event->getLocations() as $location) {
|
||||
$stream
|
||||
->addItem('LOCATION' . $location->getUri() . $location->getLanguage() . ':' . $location->getName());
|
||||
}
|
||||
|
||||
if ($event->getGeo())
|
||||
$stream->addItem('GEO:' . $event->getGeo()->getLatitude() . ';' . $event->getGeo()->getLongitude());
|
||||
|
||||
if ($event->getUrl())
|
||||
$stream->addItem('URL:' . $event->getUrl());
|
||||
|
||||
if ($event->getCreated())
|
||||
$stream->addItem('CREATED:' . $formatter->getFormattedUTCDateTime($event->getCreated()));
|
||||
|
||||
if ($event->getLastModified())
|
||||
$stream->addItem('LAST-MODIFIED:' . $formatter->getFormattedUTCDateTime($event->getLastModified()));
|
||||
|
||||
foreach ($event->getAttendees() as $attendee) {
|
||||
$stream->addItem($attendee->__toString());
|
||||
}
|
||||
|
||||
if ($event->getOrganizer())
|
||||
$stream->addItem($event->getOrganizer()->__toString());
|
||||
|
||||
$stream->addItem('END:VEVENT');
|
||||
|
||||
return $stream->getStream();
|
||||
}
|
||||
|
||||
private function formatEvent(Event $event)
|
||||
{
|
||||
/** @var CalendarEvent $calendar_event */
|
||||
$calendar_event = $event->ConvertToCalendarEvent();
|
||||
$calendar = new Calendar();
|
||||
$calendar->setProdId('-//My Company//Cool Calendar App//EN');
|
||||
$calendar->addEvent($calendar_event);
|
||||
$calendarExport = new CalendarExport(new CalendarStream, new Formatter());
|
||||
$calendarExport->addCalendar($calendar);
|
||||
|
||||
//output .ics formatted text
|
||||
$calendar_data = $calendarExport->getStream();
|
||||
|
||||
|
||||
$event_data = [
|
||||
'id' => $event->id,
|
||||
'uri' => $event->slug . '.ics',
|
||||
'lastmodified' => $event->startdate,
|
||||
'etag' => '"' . sha1($calendar_data) . '"',
|
||||
'calendarid' => 1,
|
||||
'calendardata' => $calendar_data,
|
||||
'size' => strlen($calendar_data),
|
||||
'component' => 'VEVENT',
|
||||
];
|
||||
return $event_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all calendar objects within a calendar.
|
||||
*
|
||||
* Every item contains an array with the following keys:
|
||||
* * id - unique identifier which will be used for subsequent updates
|
||||
* * calendardata - The iCalendar-compatible calendar data
|
||||
* * uri - a unique key which will be used to construct the uri. This can
|
||||
* be any arbitrary string, but making sure it ends with '.ics' is a
|
||||
* good idea. This is only the basename, or filename, not the full
|
||||
* path.
|
||||
* * lastmodified - a timestamp of the last modification time
|
||||
* * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
|
||||
* '"abcdef"')
|
||||
* * calendarid - The calendarid as it was passed to this function.
|
||||
* * size - The size of the calendar objects, in bytes.
|
||||
* * component - optional, a string containing the type of object, such
|
||||
* as 'vevent' or 'vtodo'. If specified, this will be used to populate
|
||||
* the Content-Type header.
|
||||
*
|
||||
* Note that the etag is optional, but it's highly encouraged to return for
|
||||
* speed reasons.
|
||||
*
|
||||
* The calendardata is also optional. If it's not returned
|
||||
* 'getCalendarObject' will be called later, which *is* expected to return
|
||||
* calendardata.
|
||||
*
|
||||
* If neither etag or size are specified, the calendardata will be
|
||||
* used/fetched to determine these numbers. If both are specified the
|
||||
* amount of times this is needed is reduced by a great degree.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObjects($calendarId)
|
||||
{
|
||||
/** @var EntityManager $em */
|
||||
$em = $this->controller->getDoctrine()->getManager();
|
||||
|
||||
$now = new \DateTime();
|
||||
$now->setTime(0, 0, 0);
|
||||
/** @var QueryBuilder $qb */
|
||||
$qb = $em->createQueryBuilder();
|
||||
$qb->select(array('e'))
|
||||
->from('CalciferBundle:Event', 'e')
|
||||
->orderBy('e.startdate');
|
||||
$entities = $qb->getQuery()->execute();
|
||||
|
||||
if (count($entities) > 0) {
|
||||
$events = [];
|
||||
foreach ($entities as $event) {
|
||||
/** @var Event $event */
|
||||
$events[] = $this->formatEvent($event);
|
||||
}
|
||||
return $events;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* This method must return null if the object did not exist.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return array|null
|
||||
*/
|
||||
public function getCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
/** @var EntityManager $em */
|
||||
$em = $this->controller->getDoctrine()->getManager();
|
||||
|
||||
/** @var EntityRepository $repo */
|
||||
$repo = $em->getRepository('CalciferBundle:Event');
|
||||
|
||||
/** @var Event $entity */
|
||||
$event = $repo->findOneBy(['slug' => substr($objectUri,0,strlen($objectUri) - 4)]);
|
||||
|
||||
if (!($event instanceof Event)) {
|
||||
throw $this->controller->createNotFoundException('Unable to find Event entity.');
|
||||
}
|
||||
|
||||
return $this->formatEvent($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
public function createCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
// TODO: Implement createCalendarObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: tim
|
||||
* Date: 15.11.14
|
||||
* Time: 19:45
|
||||
*/
|
||||
|
||||
namespace Hackspace\Bundle\CalciferBundle\libs;
|
||||
|
||||
use
|
||||
Sabre\DAV,
|
||||
Sabre\DAVACL,
|
||||
Sabre\HTTP\URLUtil;
|
||||
|
||||
class CalciferPrincipalBackend extends DAVACL\PrincipalBackend\AbstractBackend
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns a list of principals based on a prefix.
|
||||
*
|
||||
* This prefix will often contain something like 'principals'. You are only
|
||||
* expected to return principals that are in this base path.
|
||||
*
|
||||
* You are expected to return at least a 'uri' for every user, you can
|
||||
* return any additional properties if you wish so. Common properties are:
|
||||
* {DAV:}displayname
|
||||
* {http://sabredav.org/ns}email-address - This is a custom SabreDAV
|
||||
* field that's actually injected in a number of other properties. If
|
||||
* you have an email address, use this property.
|
||||
*
|
||||
* @param string $prefixPath
|
||||
* @return array
|
||||
*/
|
||||
function getPrincipalsByPrefix($prefixPath)
|
||||
{
|
||||
return [
|
||||
[
|
||||
'{DAV:}displayname' => 'calcifer',
|
||||
'{http://sabredav.org/ns}email-address' => 'calcifer@example.com',
|
||||
'uri' => '/caldav/calcifer',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific principal, specified by it's path.
|
||||
* The returned structure should be the exact same as from
|
||||
* getPrincipalsByPrefix.
|
||||
*
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
function getPrincipalByPath($path)
|
||||
{
|
||||
return [
|
||||
'{DAV:}displayname' => 'calcifer',
|
||||
'{http://sabredav.org/ns}email-address' => 'calcifer@example.com',
|
||||
'uri' => '/caldav/calcifer',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates one ore more webdav properties on a principal.
|
||||
*
|
||||
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
|
||||
* To do the actual updates, you must tell this object which properties
|
||||
* you're going to process with the handle() method.
|
||||
*
|
||||
* Calling the handle method is like telling the PropPatch object "I
|
||||
* promise I can handle updating this property".
|
||||
*
|
||||
* Read the PropPatch documenation for more info and examples.
|
||||
*
|
||||
* @param string $path
|
||||
* @param \Sabre\DAV\PropPatch $propPatch
|
||||
* @return void
|
||||
*/
|
||||
function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch)
|
||||
{
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to search for principals matching a set of
|
||||
* properties.
|
||||
*
|
||||
* This search is specifically used by RFC3744's principal-property-search
|
||||
* REPORT. You should at least allow searching on
|
||||
* http://sabredav.org/ns}email-address.
|
||||
*
|
||||
* The actual search should be a unicode-non-case-sensitive search. The
|
||||
* keys in searchProperties are the WebDAV property names, while the values
|
||||
* are the property values to search on.
|
||||
*
|
||||
* If multiple properties are being searched on, the search should be
|
||||
* AND'ed.
|
||||
*
|
||||
* This method should simply return an array with full principal uri's.
|
||||
*
|
||||
* If somebody attempted to search on a property the backend does not
|
||||
* support, you should simply return 0 results.
|
||||
*
|
||||
* You can also just return 0 results if you choose to not support
|
||||
* searching at all, but keep in mind that this may stop certain features
|
||||
* from working.
|
||||
*
|
||||
* @param string $prefixPath
|
||||
* @param array $searchProperties
|
||||
* @return array
|
||||
*/
|
||||
function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof')
|
||||
{
|
||||
return [
|
||||
[
|
||||
'{DAV:}displayname' => 'calcifer',
|
||||
'{http://sabredav.org/ns}email-address' => 'calcifer@example.com',
|
||||
'uri' => '/caldav/calcifer',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of members for a group-principal
|
||||
*
|
||||
* @param string $principal
|
||||
* @return array
|
||||
*/
|
||||
function getGroupMemberSet($principal)
|
||||
{
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of groups a principal is a member of
|
||||
*
|
||||
* @param string $principal
|
||||
* @return array
|
||||
*/
|
||||
function getGroupMembership($principal)
|
||||
{
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of group members for a group principal.
|
||||
*
|
||||
* The principals should be passed as a list of uri's.
|
||||
*
|
||||
* @param string $principal
|
||||
* @param array $members
|
||||
* @return void
|
||||
*/
|
||||
function setGroupMemberSet($principal, array $members)
|
||||
{
|
||||
throw new \Exception('Not implemented');
|
||||
}
|
||||
}
|
Reference in a new issue