forked from friendica/friendica-addons
Heavily refactored, including multiple calendars per user and recurring events. Not in an installable state yet, though
This commit is contained in:
parent
4a5e30ec84
commit
fefee23e90
15
dav/Changelog.txt
Normal file
15
dav/Changelog.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
v0.2.0
|
||||
======
|
||||
[FEATURE] Multiple private Calendars can be created.
|
||||
[COMPATIBILITY] When creating or updating an event using CalDAV, the etag is returned.
|
||||
|
||||
v0.1.1
|
||||
======
|
||||
[FEATURE] A "New Event" Button in the navigation bar of the calendar is added.
|
||||
[FEATURE] When creating an event by dragging in the calendar, the "Edit Details"-Link leads to a page where the details can be added before actually creating the event.
|
||||
[BUGFIX] When editing a event, the start time cannot be set befor the end time anymore.
|
||||
[BUGFIX] Fixed some problems with Magic Quotes
|
||||
|
||||
v0.1.0
|
||||
======
|
||||
Initial Release
|
|
@ -6,19 +6,24 @@ It's still in a very early stage, so expect major bugs. Please feel free to repo
|
|||
At the moment, the calendar system supports the following features:
|
||||
- A web-based drag&drop interface for managing events
|
||||
- All-Day-Events, Multi-Day-Events, and time-based events
|
||||
- Recurrences (not the whole set of options given in the iCalendar spec, but the most important ones)
|
||||
- Multiple calendars per user
|
||||
- Access to the events using CalDAV (using iPhone, Thunderbird Lightning etc., see below)
|
||||
- read-only access to the friendica-native events (also using CalDAV)
|
||||
- Read-only access to the friendica-native events (also using CalDAV)
|
||||
- The friendica-contacts are made available using CardDAV (confirmed to work with iOS)
|
||||
- Giving the subject, a description, a location and a color for the event (the color is not available through CalDAV, though)
|
||||
|
||||
|
||||
Internationalization:
|
||||
- At the moment, settings for the US and the german systems are selectable (regarding the date format and the first day of the week). More will be added on request.
|
||||
- The basic design of the system is aware of timezones; however this is not reflected in the UI yet. It currently assumes that the timezone set in the friendica-installation matches the user's local time and matches the local time set in the user's operating system.
|
||||
|
||||
CalDAV device compatibility:
|
||||
- iOS (iPhone/iPodTouch) works
|
||||
- Thunderbird Lightning should work, not tested yet
|
||||
- Android: http://dmfs.org/caldav/ seems to work, not much tested yet, though
|
||||
- Thunderbird Lightning works
|
||||
- Android:
|
||||
- aCal (http://andrew.mcmillan.net.nz/projects/aCal) works, available in F-Droid and Google Play
|
||||
- CalDAV-Sync (http://dmfs.org/caldav/) works, non-free
|
||||
|
||||
Installation
|
||||
After activating, serveral tables in the database have to be created. The admin-interface of the plugin will try to do this automatically.
|
||||
|
@ -26,10 +31,9 @@ In case of errors, the SQL-statement to create the tables manually are shown in
|
|||
|
||||
|
||||
Functuality missing: (a.k.a. "Roadmap")
|
||||
- Recurrence of events (this is only supported using the CalDAV-interface; recurring events saved using CalDAV will appear correctly multiple times in the web-based frontend; hovever those events will be read-only at the web-based frondend)
|
||||
- Sharing events; all events are private at the moment, therefore this system is not yet a complete replacement for the friendica-native events
|
||||
- Sharing events; all events are private at the moment, therefore this system is not a complete replacement for the friendica-native events
|
||||
- Attendees / Collaboration
|
||||
|
||||
- ICS Export and Import
|
||||
|
||||
|
||||
Used libraries
|
||||
|
@ -46,10 +50,6 @@ jQueryUI
|
|||
http://jqueryui.com/
|
||||
Dual-licenced: MIT and GPL licenses
|
||||
|
||||
iCalCreator
|
||||
http://kigkonsult.se/iCalcreator/
|
||||
GNU Lesser General Public License
|
||||
|
||||
TimePicker
|
||||
http://www.texotela.co.uk/code/jquery/timepicker/
|
||||
Dual-licenced: MIT and GPL licenses
|
||||
|
|
|
@ -1,31 +1,47 @@
|
|||
1.7.0-alpha (2012-??-??)
|
||||
* BC Break: The calendarobjects database table has a bunch of new fields,
|
||||
and a migration script is required to ensure everything will keep
|
||||
working. Read the wiki for more details.
|
||||
* BC Break: The calendarobjects database table has a bunch of new
|
||||
fields, and a migration script is required to ensure everything will
|
||||
keep working. Read the wiki for more details.
|
||||
* BC Break: The iCalendar interface now has a new method: calendarQuery.
|
||||
* BC Break: In this version a number of classes have been deleted, that
|
||||
have been previously deprecated. Namely:
|
||||
- Sabre_DAV_Directory (now: Sabre_DAV_Collection)
|
||||
- Sabre_DAV_SimpleDirectory (now: Sabre_DAV_SimpleCollection)
|
||||
- Sabre_VObject_Element_DateTime (now: Sabre_VObject_Property_DateTime)
|
||||
- Sabre_VObject_Element_MultiDateTime (now .._Property_MultiDateTime)
|
||||
- Sabre_VObject_Element_DateTime (now: .._Property_DateTime)
|
||||
- Sabre_VObject_Element_MultiDateTime (-> .._Property_MultiDateTime)
|
||||
* BC Break: Sabre_CalDAV_Schedule_IMip::sendMessage now has an extra
|
||||
argument. If you extended this class, you should fix this method. It's
|
||||
only used for informational purposes.
|
||||
* Changed: Responsibility for dealing with the calendar-query is now moved
|
||||
from the CalDAV plugin to the CalDAV backends. This allows for heavy
|
||||
optimizations.
|
||||
* Changed: The CalDAV PDO backend is now a lot faster for common calendar
|
||||
queries.
|
||||
* Fixed: Marking both the text/calendar and text/x-vcard as UTF-8 encoded.
|
||||
* New feature: Support for caldav notifications!
|
||||
* Changed: Responsibility for dealing with the calendar-query is now
|
||||
moved from the CalDAV plugin to the CalDAV backends. This allows for
|
||||
heavy optimizations.
|
||||
* Changed: The CalDAV PDO backend is now a lot faster for common
|
||||
calendar queries.
|
||||
* Fixed: Marking both the text/calendar and text/x-vcard as UTF-8
|
||||
encoded.
|
||||
* Fixed: Workaround for the SOGO connector, as it doesn't understand
|
||||
receiving "text/x-vcard; charset=utf-8" for a contenttype.
|
||||
* Added: Sabre_DAV_Client now throws more specific exceptions in cases
|
||||
where we already has an exception class.
|
||||
* Added: Sabre_DAV_PartialUpdate. This plugin allows you to use the PATCH
|
||||
method to update parts of a file.
|
||||
* Added: Sabre_DAV_PartialUpdate. This plugin allows you to use the
|
||||
PATCH method to update parts of a file.
|
||||
* Added: Tons of timezone name mappings for Microsoft Exchange.
|
||||
* Added: Support for an 'exception' event.
|
||||
* Fixed: Uploaded VCards without a UID are now rejected. (thanks Dominik!)
|
||||
* Fixed: Rejecting calendar objects if they are not in the
|
||||
supported-calendar-component list. (thanks Armin!)
|
||||
|
||||
1.6.3-stable (2012-??-??)
|
||||
1.6.4-stable (2012-??-??)
|
||||
* Fixed: Issue 220: Calendar-query filters may fail when filtering on
|
||||
alarms, if an overridden event has it's alarm removed.
|
||||
* Fixed: Compatibility for OS/X 10.8 iCal in the IMipHandler.
|
||||
* Fixed: Issue 222: beforeWriteContent shouldn't be called for lock
|
||||
requests.
|
||||
* Fixed: Problem with POST requests to the outbox if mailto: was not lower
|
||||
cased.
|
||||
|
||||
1.6.3-stable (2012-06-12)
|
||||
* Added: It's now possible to specify in Sabre_DAV_Client which type of
|
||||
authentication is to be used.
|
||||
* Fixed: Issue 206: Sabre_DAV_Client PUT requests are fixed.
|
||||
|
@ -43,6 +59,7 @@
|
|||
compatibility.
|
||||
* Fixed: Added a workaround for a bug in KDE 4.8.2 contact syncing. See
|
||||
https://bugs.kde.org/show_bug.cgi?id=300047
|
||||
* Fixed: Issue 217: Sabre_DAV_Tree_FileSystem was pretty broken.
|
||||
|
||||
1.6.2-stable (2012-04-16)
|
||||
* Fixed: Sabre_VObject_Node::$parent should have been public.
|
||||
|
|
|
@ -95,6 +95,11 @@ foreach($fields17 as $field) {
|
|||
if ($found === 0) {
|
||||
echo "The database had the 1.6 schema. Table will now be altered.\n";
|
||||
echo "This may take some time for large tables\n";
|
||||
|
||||
switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
|
||||
|
||||
case 'mysql' :
|
||||
|
||||
$pdo->exec(<<<SQL
|
||||
ALTER TABLE calendarobjects
|
||||
ADD etag VARCHAR(32),
|
||||
|
@ -104,6 +109,19 @@ ADD firstoccurence INT(11) UNSIGNED,
|
|||
ADD lastoccurence INT(11) UNSIGNED
|
||||
SQL
|
||||
);
|
||||
break;
|
||||
case 'sqlite' :
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD etag text');
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD size integer');
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD componenttype TEXT');
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD firstoccurence integer');
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD lastoccurence integer');
|
||||
break;
|
||||
|
||||
default :
|
||||
die('This upgrade script does not support this driver (' . $pdo->getAttribute(PDO::ATTR_DRIVER_NAME) . ")\n");
|
||||
|
||||
}
|
||||
echo "Database schema upgraded.\n";
|
||||
|
||||
} elseif ($found === 5) {
|
||||
|
|
1568
dav/SabreDAV/docs/caldav-notifications.txt
Normal file
1568
dav/SabreDAV/docs/caldav-notifications.txt
Normal file
File diff suppressed because it is too large
Load diff
224
dav/SabreDAV/docs/caldav-sharing-02.txt
Normal file
224
dav/SabreDAV/docs/caldav-sharing-02.txt
Normal file
File diff suppressed because one or more lines are too long
451
dav/SabreDAV/docs/rfc5785.txt
Normal file
451
dav/SabreDAV/docs/rfc5785.txt
Normal file
|
@ -0,0 +1,451 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Internet Engineering Task Force (IETF) M. Nottingham
|
||||
Request for Comments: 5785 E. Hammer-Lahav
|
||||
Updates: 2616, 2818 April 2010
|
||||
Category: Standards Track
|
||||
ISSN: 2070-1721
|
||||
|
||||
|
||||
Defining Well-Known Uniform Resource Identifiers (URIs)
|
||||
|
||||
Abstract
|
||||
|
||||
This memo defines a path prefix for "well-known locations",
|
||||
"/.well-known/", in selected Uniform Resource Identifier (URI)
|
||||
schemes.
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This is an Internet Standards Track document.
|
||||
|
||||
This document is a product of the Internet Engineering Task Force
|
||||
(IETF). It represents the consensus of the IETF community. It has
|
||||
received public review and has been approved for publication by the
|
||||
Internet Engineering Steering Group (IESG). Further information on
|
||||
Internet Standards is available in Section 2 of RFC 5741.
|
||||
|
||||
Information about the current status of this document, any errata,
|
||||
and how to provide feedback on it may be obtained at
|
||||
http://www.rfc-editor.org/info/rfc5785.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (c) 2010 IETF Trust and the persons identified as the
|
||||
document authors. All rights reserved.
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info) in effect on the date of
|
||||
publication of this document. Please review these documents
|
||||
carefully, as they describe your rights and restrictions with respect
|
||||
to this document. Code Components extracted from this document must
|
||||
include Simplified BSD License text as described in Section 4.e of
|
||||
the Trust Legal Provisions and are provided without warranty as
|
||||
described in the Simplified BSD License.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 1]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
1.1. Appropriate Use of Well-Known URIs . . . . . . . . . . . . 3
|
||||
2. Notational Conventions . . . . . . . . . . . . . . . . . . . . 3
|
||||
3. Well-Known URIs . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
4. Security Considerations . . . . . . . . . . . . . . . . . . . . 4
|
||||
5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
5.1. The Well-Known URI Registry . . . . . . . . . . . . . . . . 4
|
||||
5.1.1. Registration Template . . . . . . . . . . . . . . . . . 5
|
||||
6. References . . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
6.1. Normative References . . . . . . . . . . . . . . . . . . . 5
|
||||
6.2. Informative References . . . . . . . . . . . . . . . . . . 5
|
||||
Appendix A. Acknowledgements . . . . . . . . . . . . . . . . . . . 7
|
||||
Appendix B. Frequently Asked Questions . . . . . . . . . . . . . . 7
|
||||
|
||||
1. Introduction
|
||||
|
||||
It is increasingly common for Web-based protocols to require the
|
||||
discovery of policy or other information about a host ("site-wide
|
||||
metadata") before making a request. For example, the Robots
|
||||
Exclusion Protocol <http://www.robotstxt.org/> specifies a way for
|
||||
automated processes to obtain permission to access resources;
|
||||
likewise, the Platform for Privacy Preferences [W3C.REC-P3P-20020416]
|
||||
tells user-agents how to discover privacy policy beforehand.
|
||||
|
||||
While there are several ways to access per-resource metadata (e.g.,
|
||||
HTTP headers, WebDAV's PROPFIND [RFC4918]), the perceived overhead
|
||||
(either in terms of client-perceived latency and/or deployment
|
||||
difficulties) associated with them often precludes their use in these
|
||||
scenarios.
|
||||
|
||||
When this happens, it is common to designate a "well-known location"
|
||||
for such data, so that it can be easily located. However, this
|
||||
approach has the drawback of risking collisions, both with other such
|
||||
designated "well-known locations" and with pre-existing resources.
|
||||
|
||||
To address this, this memo defines a path prefix in HTTP(S) URIs for
|
||||
these "well-known locations", "/.well-known/". Future specifications
|
||||
that need to define a resource for such site-wide metadata can
|
||||
register their use to avoid collisions and minimise impingement upon
|
||||
sites' URI space.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 2]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
1.1. Appropriate Use of Well-Known URIs
|
||||
|
||||
There are a number of possible ways that applications could use Well-
|
||||
known URIs. However, in keeping with the Architecture of the World-
|
||||
Wide Web [W3C.REC-webarch-20041215], well-known URIs are not intended
|
||||
for general information retrieval or establishment of large URI
|
||||
namespaces on the Web. Rather, they are designed to facilitate
|
||||
discovery of information on a site when it isn't practical to use
|
||||
other mechanisms; for example, when discovering policy that needs to
|
||||
be evaluated before a resource is accessed, or when using multiple
|
||||
round-trips is judged detrimental to performance.
|
||||
|
||||
As such, the well-known URI space was created with the expectation
|
||||
that it will be used to make site-wide policy information and other
|
||||
metadata available directly (if sufficiently concise), or provide
|
||||
references to other URIs that provide such metadata.
|
||||
|
||||
2. Notational Conventions
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
3. Well-Known URIs
|
||||
|
||||
A well-known URI is a URI [RFC3986] whose path component begins with
|
||||
the characters "/.well-known/", and whose scheme is "HTTP", "HTTPS",
|
||||
or another scheme that has explicitly been specified to use well-
|
||||
known URIs.
|
||||
|
||||
Applications that wish to mint new well-known URIs MUST register
|
||||
them, following the procedures in Section 5.1.
|
||||
|
||||
For example, if an application registers the name 'example', the
|
||||
corresponding well-known URI on 'http://www.example.com/' would be
|
||||
'http://www.example.com/.well-known/example'.
|
||||
|
||||
Registered names MUST conform to the segment-nz production in
|
||||
[RFC3986].
|
||||
|
||||
Note that this specification defines neither how to determine the
|
||||
authority to use for a particular context, nor the scope of the
|
||||
metadata discovered by dereferencing the well-known URI; both should
|
||||
be defined by the application itself.
|
||||
|
||||
Typically, a registration will reference a specification that defines
|
||||
the format and associated media type to be obtained by dereferencing
|
||||
the well-known URI.
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 3]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
It MAY also contain additional information, such as the syntax of
|
||||
additional path components, query strings and/or fragment identifiers
|
||||
to be appended to the well-known URI, or protocol-specific details
|
||||
(e.g., HTTP [RFC2616] method handling).
|
||||
|
||||
Note that this specification does not define a format or media-type
|
||||
for the resource located at "/.well-known/" and clients should not
|
||||
expect a resource to exist at that location.
|
||||
|
||||
4. Security Considerations
|
||||
|
||||
This memo does not specify the scope of applicability of metadata or
|
||||
policy obtained from a well-known URI, and does not specify how to
|
||||
discover a well-known URI for a particular application. Individual
|
||||
applications using this mechanism must define both aspects.
|
||||
|
||||
Applications minting new well-known URIs, as well as administrators
|
||||
deploying them, will need to consider several security-related
|
||||
issues, including (but not limited to) exposure of sensitive data,
|
||||
denial-of-service attacks (in addition to normal load issues), server
|
||||
and client authentication, vulnerability to DNS rebinding attacks,
|
||||
and attacks where limited access to a server grants the ability to
|
||||
affect how well-known URIs are served.
|
||||
|
||||
5. IANA Considerations
|
||||
|
||||
5.1. The Well-Known URI Registry
|
||||
|
||||
This document establishes the well-known URI registry.
|
||||
|
||||
Well-known URIs are registered on the advice of one or more
|
||||
Designated Experts (appointed by the IESG or their delegate), with a
|
||||
Specification Required (using terminology from [RFC5226]). However,
|
||||
to allow for the allocation of values prior to publication, the
|
||||
Designated Expert(s) may approve registration once they are satisfied
|
||||
that such a specification will be published.
|
||||
|
||||
Registration requests should be sent to the
|
||||
wellknown-uri-review@ietf.org mailing list for review and comment,
|
||||
with an appropriate subject (e.g., "Request for well-known URI:
|
||||
example").
|
||||
|
||||
Before a period of 14 days has passed, the Designated Expert(s) will
|
||||
either approve or deny the registration request, communicating this
|
||||
decision both to the review list and to IANA. Denials should include
|
||||
an explanation and, if applicable, suggestions as to how to make the
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 4]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
request successful. Registration requests that are undetermined for
|
||||
a period longer than 21 days can be brought to the IESG's attention
|
||||
(using the iesg@iesg.org mailing list) for resolution.
|
||||
|
||||
5.1.1. Registration Template
|
||||
|
||||
URI suffix: The name requested for the well-known URI, relative to
|
||||
"/.well-known/"; e.g., "example".
|
||||
|
||||
Change controller: For Standards-Track RFCs, state "IETF". For
|
||||
others, give the name of the responsible party. Other details
|
||||
(e.g., postal address, e-mail address, home page URI) may also be
|
||||
included.
|
||||
|
||||
Specification document(s): Reference to the document that specifies
|
||||
the field, preferably including a URI that can be used to retrieve
|
||||
a copy of the document. An indication of the relevant sections
|
||||
may also be included, but is not required.
|
||||
|
||||
Related information: Optionally, citations to additional documents
|
||||
containing further relevant information.
|
||||
|
||||
6. References
|
||||
|
||||
6.1. Normative References
|
||||
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
|
||||
Resource Identifier (URI): Generic Syntax", STD 66,
|
||||
RFC 3986, January 2005.
|
||||
|
||||
[RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an
|
||||
IANA Considerations Section in RFCs", BCP 26, RFC 5226,
|
||||
May 2008.
|
||||
|
||||
6.2. Informative References
|
||||
|
||||
[RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter,
|
||||
L., Leach, P., and T. Berners-Lee, "Hypertext Transfer
|
||||
Protocol -- HTTP/1.1", RFC 2616, June 1999.
|
||||
|
||||
[RFC4918] Dusseault, L., "HTTP Extensions for Web Distributed
|
||||
Authoring and Versioning (WebDAV)", RFC 4918, June 2007.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 5]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
[W3C.REC-P3P-20020416]
|
||||
Marchiori, M., "The Platform for Privacy Preferences 1.0
|
||||
(P3P1.0) Specification", World Wide Web Consortium
|
||||
Recommendation REC-P3P-20020416, April 2002,
|
||||
<http://www.w3.org/TR/2002/ REC-P3P-20020416>.
|
||||
|
||||
[W3C.REC-webarch-20041215]
|
||||
Jacobs, I. and N. Walsh, "Architecture of the World Wide
|
||||
Web, Volume One", World Wide Web Consortium
|
||||
Recommendation REC- webarch-20041215, December 2004,
|
||||
<http:// www.w3.org/TR/2004/REC-webarch-20041215>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 6]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
Appendix A. Acknowledgements
|
||||
|
||||
We would like to acknowledge the contributions of everyone who
|
||||
provided feedback and use cases for this document; in particular,
|
||||
Phil Archer, Dirk Balfanz, Adam Barth, Tim Bray, Brian Eaton, Brad
|
||||
Fitzpatrick, Joe Gregorio, Paul Hoffman, Barry Leiba, Ashok Malhotra,
|
||||
Breno de Medeiros, John Panzer, and Drummond Reed. However, they are
|
||||
not responsible for errors and omissions.
|
||||
|
||||
Appendix B. Frequently Asked Questions
|
||||
|
||||
1. Aren't well-known locations bad for the Web?
|
||||
|
||||
They are, but for various reasons -- both technical and social --
|
||||
they are commonly used and their use is increasing. This memo
|
||||
defines a "sandbox" for them, to reduce the risks of collision and
|
||||
to minimise the impact upon pre-existing URIs on sites.
|
||||
|
||||
2. Why /.well-known?
|
||||
|
||||
It's short, descriptive, and according to search indices, not
|
||||
widely used.
|
||||
|
||||
3. What impact does this have on existing mechanisms, such as P3P and
|
||||
robots.txt?
|
||||
|
||||
None, until they choose to use this mechanism.
|
||||
|
||||
4. Why aren't per-directory well-known locations defined?
|
||||
|
||||
Allowing every URI path segment to have a well-known location
|
||||
(e.g., "/images/.well-known/") would increase the risks of
|
||||
colliding with a pre-existing URI on a site, and generally these
|
||||
solutions are found not to scale well, because they're too
|
||||
"chatty".
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 7]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Mark Nottingham
|
||||
|
||||
EMail: mnot@mnot.net
|
||||
URI: http://www.mnot.net/
|
||||
|
||||
|
||||
Eran Hammer-Lahav
|
||||
|
||||
EMail: eran@hueniverse.com
|
||||
URI: http://hueniverse.com/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 8]
|
||||
|
|
@ -3,45 +3,15 @@
|
|||
/**
|
||||
* Abstract Calendaring backend. Extend this class to create your own backends.
|
||||
*
|
||||
* Checkout the BackendInterface for all the methods that must be implemented.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_CalDAV_Backend_Abstract {
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
abstract function getCalendarsForUser($principalUri);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
abstract function createCalendar($principalUri,$calendarUri,array $properties);
|
||||
abstract class Sabre_CalDAV_Backend_Abstract implements Sabre_CalDAV_Backend_BackendInterface {
|
||||
|
||||
/**
|
||||
* Updates properties for a calendar.
|
||||
|
@ -85,102 +55,6 @@ abstract class Sabre_CalDAV_Backend_Abstract {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @return void
|
||||
*/
|
||||
abstract function deleteCalendar($calendarId);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* * 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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
abstract function getCalendarObjects($calendarId);
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return array
|
||||
*/
|
||||
abstract function getCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
abstract function createCalendarObject($calendarId,$objectUri,$calendarData);
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
abstract function updateCalendarObject($calendarId,$objectUri,$calendarData);
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
abstract function deleteCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Performs a calendar-query on the contents of this calendar.
|
||||
*
|
||||
|
|
231
dav/SabreDAV/lib/Sabre/CalDAV/Backend/BackendInterface.php
Normal file
231
dav/SabreDAV/lib/Sabre/CalDAV/Backend/BackendInterface.php
Normal file
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Every CalDAV backend must at least implement this interface.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CalDAV_Backend_BackendInterface {
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Updates properties for a calendar.
|
||||
*
|
||||
* The mutations array uses the propertyName in clark-notation as key,
|
||||
* and the array value for the property value. In the case a property
|
||||
* should be deleted, the property value will be null.
|
||||
*
|
||||
* This method must be atomic. If one property cannot be changed, the
|
||||
* entire operation must fail.
|
||||
*
|
||||
* If the operation was successful, true can be returned.
|
||||
* If the operation failed, false can be returned.
|
||||
*
|
||||
* Deletion of a non-existent property is always successful.
|
||||
*
|
||||
* Lastly, it is optional to return detailed information about any
|
||||
* failures. In this case an array should be returned with the following
|
||||
* structure:
|
||||
*
|
||||
* array(
|
||||
* 403 => array(
|
||||
* '{DAV:}displayname' => null,
|
||||
* ),
|
||||
* 424 => array(
|
||||
* '{DAV:}owner' => null,
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* In this example it was forbidden to update {DAV:}displayname.
|
||||
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
|
||||
* (424 Failed Dependency) because the request needs to be atomic.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateCalendar($calendarId, array $mutations);
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* * 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.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Performs a calendar-query on the contents of this calendar.
|
||||
*
|
||||
* The calendar-query is defined in RFC4791 : CalDAV. Using the
|
||||
* calendar-query it is possible for a client to request a specific set of
|
||||
* object, based on contents of iCalendar properties, date-ranges and
|
||||
* iCalendar component types (VTODO, VEVENT).
|
||||
*
|
||||
* This method should just return a list of (relative) urls that match this
|
||||
* query.
|
||||
*
|
||||
* The list of filters are specified as an array. The exact array is
|
||||
* documented by Sabre_CalDAV_CalendarQueryParser.
|
||||
*
|
||||
* Note that it is extremely likely that getCalendarObject for every path
|
||||
* returned from this method will be called almost immediately after. You
|
||||
* may want to anticipate this to speed up these requests.
|
||||
*
|
||||
* This method provides a default implementation, which parses *all* the
|
||||
* iCalendar objects in the specified calendar.
|
||||
*
|
||||
* This default may well be good enough for personal use, and calendars
|
||||
* that aren't very large. But if you anticipate high usage, big calendars
|
||||
* or high loads, you are strongly adviced to optimize certain paths.
|
||||
*
|
||||
* The best way to do so is override this method and to optimize
|
||||
* specifically for 'common filters'.
|
||||
*
|
||||
* Requests that are extremely common are:
|
||||
* * requests for just VEVENTS
|
||||
* * requests for just VTODO
|
||||
* * requests with a time-range-filter on either VEVENT or VTODO.
|
||||
*
|
||||
* ..and combinations of these requests. It may not be worth it to try to
|
||||
* handle every possible situation and just rely on the (relatively
|
||||
* easy to use) CalendarQueryValidator to handle the rest.
|
||||
*
|
||||
* Note that especially time-range-filters may be difficult to parse. A
|
||||
* time-range filter specified on a VEVENT must for instance also handle
|
||||
* recurrence rules correctly.
|
||||
* A good example of how to interprete all these filters can also simply
|
||||
* be found in Sabre_CalDAV_CalendarQueryFilter. This class is as correct
|
||||
* as possible, so it gives you a good idea on what type of stuff you need
|
||||
* to think of.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param array $filters
|
||||
* @return array
|
||||
*/
|
||||
public function calendarQuery($calendarId, array $filters);
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Adds caldav notification support to a backend.
|
||||
*
|
||||
* Notifications are defined at:
|
||||
* http://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk/doc/Extensions/caldav-notifications.txt
|
||||
*
|
||||
* These notifications are basically a list of server-generated notifications
|
||||
* displayed to the user. Users can dismiss notifications by deleting them.
|
||||
*
|
||||
* The primary usecase is to allow for calendar-sharing.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CalDAV_Backend_NotificationSupport extends Sabre_CalDAV_Backend_BackendInterface {
|
||||
|
||||
/**
|
||||
* Returns a list of notifications for a given principal url.
|
||||
*
|
||||
* The returned array should only consist of implementations of
|
||||
* Sabre_CalDAV_Notifications_INotificationType.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getNotificationsForPrincipal($principalUri);
|
||||
|
||||
/**
|
||||
* This deletes a specific notifcation.
|
||||
*
|
||||
* This may be called by a client once it deems a notification handled.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param Sabre_CalDAV_Notifications_INotificationType $notification
|
||||
* @return void
|
||||
*/
|
||||
public function deleteNotification($principalUri, Sabre_CalDAV_Notifications_INotificationType $notification);
|
||||
|
||||
}
|
|
@ -24,7 +24,7 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
|
|||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
* @var Sabre_CalDAV_Backend_BackendInterface
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
|
@ -39,10 +39,10 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
|
|||
* Constructor
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param Sabre_CalDAV_Backend_BackendInterface $caldavBackend
|
||||
* @param array $calendarInfo
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_Abstract $caldavBackend, $calendarInfo) {
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_BackendInterface $caldavBackend, $calendarInfo) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
$this->principalBackend = $principalBackend;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV_ICalendarObject, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
* Sabre_CalDAV_Backend_Abstract
|
||||
* Sabre_CalDAV_Backend_BackendInterface
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
@ -35,11 +35,11 @@ class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV
|
|||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param Sabre_CalDAV_Backend_BackendInterface $caldavBackend
|
||||
* @param array $calendarInfo
|
||||
* @param array $objectData
|
||||
*/
|
||||
public function __construct(Sabre_CalDAV_Backend_Abstract $caldavBackend,array $calendarInfo,array $objectData) {
|
||||
public function __construct(Sabre_CalDAV_Backend_BackendInterface $caldavBackend,array $calendarInfo,array $objectData) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
|
||||
|
|
|
@ -304,6 +304,7 @@ class Sabre_CalDAV_CalendarQueryValidator {
|
|||
// one is the first to trigger. Based on this, we can
|
||||
// determine if we can 'give up' expanding events.
|
||||
$firstAlarm = null;
|
||||
if ($expandedEvent->VALARM !== null) {
|
||||
foreach($expandedEvent->VALARM as $expandedAlarm) {
|
||||
|
||||
$effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
|
||||
|
@ -325,7 +326,7 @@ class Sabre_CalDAV_CalendarQueryValidator {
|
|||
$firstAlarm = $effectiveTrigger;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (is_null($firstAlarm)) {
|
||||
// No alarm was found.
|
||||
|
|
|
@ -17,7 +17,7 @@ class Sabre_CalDAV_CalendarRootNode extends Sabre_DAVACL_AbstractPrincipalCollec
|
|||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
* @var Sabre_CalDAV_Backend_BackendInterface
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
|
@ -33,10 +33,10 @@ class Sabre_CalDAV_CalendarRootNode extends Sabre_DAVACL_AbstractPrincipalCollec
|
|||
*
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param Sabre_CalDAV_Backend_BackendInterface $caldavBackend
|
||||
* @param string $principalPrefix
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend,Sabre_CalDAV_Backend_Abstract $caldavBackend, $principalPrefix = 'principals') {
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend,Sabre_CalDAV_Backend_BackendInterface $caldavBackend, $principalPrefix = 'principals') {
|
||||
|
||||
parent::__construct($principalBackend, $principalPrefix);
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Sabre_CalDAV_Exception_InvalidComponentType
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Exception_InvalidComponentType extends Sabre_DAV_Exception_Forbidden {
|
||||
|
||||
/**
|
||||
* Adds in extra information in the xml response.
|
||||
*
|
||||
* This method adds the {CALDAV:}supported-calendar-component as defined in rfc4791
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
$doc = $errorNode->ownerDocument;
|
||||
|
||||
$np = $doc->createElementNS(Sabre_CalDAV_Plugin::NS_CALDAV,'cal:supported-calendar-component');
|
||||
$errorNode->appendChild($np);
|
||||
|
||||
}
|
||||
|
||||
}
|
80
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/Collection.php
Normal file
80
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/Collection.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This node represents a list of notifications.
|
||||
*
|
||||
* It provides no additional functionality, but you must implement this
|
||||
* interface to allow the Notifications plugin to mark the collection
|
||||
* as a notifications collection.
|
||||
*
|
||||
* This collection should only return Sabre_CalDAV_Notifications_INode nodes as
|
||||
* its children.
|
||||
*
|
||||
* @package Sabre
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Notifications_Collection extends Sabre_DAV_Collection implements Sabre_CalDAV_Notifications_ICollection {
|
||||
|
||||
/**
|
||||
* The notification backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_NotificationSupport
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
/**
|
||||
* Principal uri
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $principalUri;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CalDAV_Backend_NotificationSupport $caldavBackend
|
||||
* @param string $principalUri
|
||||
*/
|
||||
public function __construct(Sabre_CalDAV_Backend_NotificationSupport $caldavBackend, $principalUri) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
$this->principalUri = $principalUri;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all notifications for a principal
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
$children = array();
|
||||
$notifications = $this->caldavBackend->getNotificationsForPrincipal($this->principalUri);
|
||||
|
||||
foreach($notifications as $notification) {
|
||||
|
||||
$children[] = new Sabre_CalDAV_Notifications_Node(
|
||||
$this->caldavBackend,
|
||||
$notification
|
||||
);
|
||||
}
|
||||
|
||||
return $children;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return 'notifications';
|
||||
|
||||
}
|
||||
|
||||
}
|
22
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/ICollection.php
Normal file
22
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/ICollection.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This node represents a list of notifications.
|
||||
*
|
||||
* It provides no additional functionality, but you must implement this
|
||||
* interface to allow the Notifications plugin to mark the collection
|
||||
* as a notifications collection.
|
||||
*
|
||||
* This collection should only return Sabre_CalDAV_Notifications_INode nodes as
|
||||
* its children.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CalDAV_Notifications_ICollection extends Sabre_DAV_ICollection {
|
||||
|
||||
|
||||
}
|
29
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/INode.php
Normal file
29
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/INode.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This node represents a single notification.
|
||||
*
|
||||
* The signature is mostly identical to that of Sabre_DAV_IFile, but the get() method
|
||||
* MUST return an xml document that matches the requirements of the
|
||||
* 'caldav-notifications.txt' spec.
|
||||
*
|
||||
* For a complete example, check out the Notification class, which contains
|
||||
* some helper functions.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CalDAV_Notifications_INode {
|
||||
|
||||
/**
|
||||
* This method must return an xml element, using the
|
||||
* Sabre_CalDAV_Notifications_INotificationType classes.
|
||||
*
|
||||
* @return Sabre_DAVNotification_INotificationType
|
||||
*/
|
||||
function getNotificationType();
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This interface reflects a single notification type.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CalDAV_Notifications_INotificationType extends Sabre_DAV_PropertyInterface {
|
||||
|
||||
/**
|
||||
* Serializes the notification as a single property.
|
||||
*
|
||||
* You should usually just encode the single top-level element of the
|
||||
* notification.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
function serialize(Sabre_DAV_Server $server, \DOMElement $node);
|
||||
|
||||
/**
|
||||
* This method serializes the entire notification, as it is used in the
|
||||
* response body.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
function serializeBody(Sabre_DAV_Server $server, \DOMElement $node);
|
||||
|
||||
/**
|
||||
* Returns a unique id for this notification
|
||||
*
|
||||
* This is just the base url. This should generally be some kind of unique
|
||||
* id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getId();
|
||||
|
||||
}
|
68
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/Node.php
Normal file
68
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/Node.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This node represents a single notification.
|
||||
*
|
||||
* The signature is mostly identical to that of Sabre_DAV_IFile, but the get() method
|
||||
* MUST return an xml document that matches the requirements of the
|
||||
* 'caldav-notifications.txt' spec.
|
||||
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Notifications_Node extends Sabre_DAV_Node implements Sabre_CalDAV_Notifications_INode {
|
||||
|
||||
/**
|
||||
* The notification backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_NotificationSupport
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
/**
|
||||
* The actual notification
|
||||
*
|
||||
* @var Sabre_CalDAV_Notifications_INotificationType
|
||||
*/
|
||||
protected $notification;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CalDAV_Backend_NotificationSupport $caldavBackend
|
||||
* @param Sabre_CalDAV_Notifications_INotificationType $notification
|
||||
*/
|
||||
public function __construct(Sabre_CalDAV_Backend_NotificationSupport $caldavBackend, Sabre_CalDAV_Notifications_INotificationType $notification) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
$this->notification = $notification;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path name for this notification
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return $this->notification->getId();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method must return an xml element, using the
|
||||
* Sabre_CalDAV_Notifications_INotificationType classes.
|
||||
*
|
||||
* @return Sabre_DAVNotification_INotificationType
|
||||
*/
|
||||
public function getNotificationType() {
|
||||
|
||||
return $this->notification;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SystemStatus notification
|
||||
*
|
||||
* This notification can be used to indicate to the user that the system is
|
||||
* down.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Notifications_Notification_SystemStatus extends Sabre_DAV_Property implements Sabre_CalDAV_Notifications_INotificationType {
|
||||
|
||||
const TYPE_LOW = 1;
|
||||
const TYPE_MEDIUM = 2;
|
||||
const TYPE_HIGH = 3;
|
||||
|
||||
/**
|
||||
* A unique id
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The type of alert. This should be one of the TYPE_ constants.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* A human-readable description of the problem.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* A url to a website with more information for the user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $href;
|
||||
|
||||
/**
|
||||
* Creates the notification.
|
||||
*
|
||||
* Some kind of unique id should be provided. This is used to generate a
|
||||
* url.
|
||||
*
|
||||
* @param string $id
|
||||
* @param int $type
|
||||
* @param string $description
|
||||
* @param string $href
|
||||
*/
|
||||
public function __construct($id, $type = self::TYPE_HIGH, $description = null, $href = null) {
|
||||
|
||||
$this->id = $id;
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
$this->href = $href;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the notification as a single property.
|
||||
*
|
||||
* You should usually just encode the single top-level element of the
|
||||
* notification.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server, \DOMElement $node) {
|
||||
|
||||
switch($this->type) {
|
||||
case self::TYPE_LOW :
|
||||
$type = 'low';
|
||||
break;
|
||||
case self::TYPE_MEDIUM :
|
||||
$type = 'medium';
|
||||
break;
|
||||
default :
|
||||
case self::TYPE_HIGH :
|
||||
$type = 'high';
|
||||
break;
|
||||
}
|
||||
|
||||
$prop = $node->ownerDocument->createElement('cs:systemstatus');
|
||||
$prop->setAttribute('type', $type);
|
||||
|
||||
$node->appendChild($prop);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method serializes the entire notification, as it is used in the
|
||||
* response body.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
public function serializeBody(Sabre_DAV_Server $server, \DOMElement $node) {
|
||||
|
||||
switch($this->type) {
|
||||
case self::TYPE_LOW :
|
||||
$type = 'low';
|
||||
break;
|
||||
case self::TYPE_MEDIUM :
|
||||
$type = 'medium';
|
||||
break;
|
||||
default :
|
||||
case self::TYPE_HIGH :
|
||||
$type = 'high';
|
||||
break;
|
||||
}
|
||||
|
||||
$prop = $node->ownerDocument->createElement('cs:systemstatus');
|
||||
$prop->setAttribute('type', $type);
|
||||
|
||||
if ($this->description) {
|
||||
$text = $node->ownerDocument->createTextNode($this->description);
|
||||
$desc = $node->ownerDocument->createElement('cs:description');
|
||||
$desc->appendChild($text);
|
||||
$prop->appendChild($desc);
|
||||
}
|
||||
if ($this->href) {
|
||||
$text = $node->ownerDocument->createTextNode($this->href);
|
||||
$href = $node->ownerDocument->createElement('d:href');
|
||||
$href->appendChild($text);
|
||||
$prop->appendChild($href);
|
||||
}
|
||||
|
||||
$node->appendChild($prop);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique id for this notification
|
||||
*
|
||||
* This is just the base url. This should generally be some kind of unique
|
||||
* id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId() {
|
||||
|
||||
return $this->id;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -162,6 +162,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
$server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction'));
|
||||
$server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent'));
|
||||
$server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile'));
|
||||
$server->subscribeEvent('beforeMethod', array($this,'beforeMethod'));
|
||||
|
||||
$server->xmlNamespaces[self::NS_CALDAV] = 'cal';
|
||||
$server->xmlNamespaces[self::NS_CALENDARSERVER] = 'cs';
|
||||
|
@ -172,6 +173,8 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
$server->resourceTypeMapping['Sabre_CalDAV_Schedule_IOutbox'] = '{urn:ietf:params:xml:ns:caldav}schedule-outbox';
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_Principal_ProxyRead'] = '{http://calendarserver.org/ns/}calendar-proxy-read';
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_Principal_ProxyWrite'] = '{http://calendarserver.org/ns/}calendar-proxy-write';
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_Notifications_ICollection'] = '{' . self::NS_CALENDARSERVER . '}notifications';
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_Notifications_INode'] = '{' . self::NS_CALENDARSERVER . '}notification';
|
||||
|
||||
array_push($server->protectedProperties,
|
||||
|
||||
|
@ -195,7 +198,9 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
// CalendarServer extensions
|
||||
'{' . self::NS_CALENDARSERVER . '}getctag',
|
||||
'{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for',
|
||||
'{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for'
|
||||
'{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for',
|
||||
'{' . self::NS_CALENDARSERVER . '}notification-URL',
|
||||
'{' . self::NS_CALENDARSERVER . '}notificationtype'
|
||||
|
||||
);
|
||||
}
|
||||
|
@ -380,8 +385,31 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
}
|
||||
|
||||
// notification-URL property
|
||||
$notificationUrl = '{' . self::NS_CALENDARSERVER . '}notification-URL';
|
||||
if (($index = array_search($notificationUrl, $requestedProperties)) !== false) {
|
||||
$principalId = $node->getName();
|
||||
$calendarHomePath = 'calendars/' . $principalId . '/notifications/';
|
||||
unset($requestedProperties[$index]);
|
||||
$returnedProperties[200][$notificationUrl] = new Sabre_DAV_Property_Href($calendarHomePath);
|
||||
}
|
||||
|
||||
} // instanceof IPrincipal
|
||||
|
||||
if ($node instanceof Sabre_CalDAV_Notifications_INode) {
|
||||
|
||||
$propertyName = '{' . self::NS_CALENDARSERVER . '}notificationtype';
|
||||
if (($index = array_search($propertyName, $requestedProperties)) !== false) {
|
||||
|
||||
$returnedProperties[200][$propertyName] =
|
||||
$node->getNotificationType();
|
||||
|
||||
unset($requestedProperties[$index]);
|
||||
|
||||
}
|
||||
|
||||
} // instanceof Notifications_INode
|
||||
|
||||
|
||||
if ($node instanceof Sabre_CalDAV_ICalendarObject) {
|
||||
// The calendar-data property is not supposed to be a 'real'
|
||||
|
@ -648,7 +676,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
if (!$node instanceof Sabre_CalDAV_ICalendarObject)
|
||||
return;
|
||||
|
||||
$this->validateICalendar($data);
|
||||
$this->validateICalendar($data, $path);
|
||||
|
||||
}
|
||||
|
||||
|
@ -668,7 +696,49 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
if (!$parentNode instanceof Sabre_CalDAV_Calendar)
|
||||
return;
|
||||
|
||||
$this->validateICalendar($data);
|
||||
$this->validateICalendar($data, $path);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is triggered before any HTTP request is handled.
|
||||
*
|
||||
* We use this to intercept GET calls to notification nodes, and return the
|
||||
* proper response.
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function beforeMethod($method, $path) {
|
||||
|
||||
if ($method!=='GET') return;
|
||||
|
||||
try {
|
||||
$node = $this->server->tree->getNodeForPath($path);
|
||||
} catch (Sabre_DAV_Exception_NotFound $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$node instanceof Sabre_CalDAV_Notifications_INode)
|
||||
return;
|
||||
|
||||
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
|
||||
$root = $dom->createElement('cs:notification');
|
||||
foreach($this->server->xmlNamespaces as $namespace => $prefix) {
|
||||
$root->setAttribute('xmlns:' . $prefix, $namespace);
|
||||
}
|
||||
|
||||
$dom->appendChild($root);
|
||||
$node->getNotificationType()->serializeBody($this->server, $root);
|
||||
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml');
|
||||
$this->server->httpResponse->sendStatus(200);
|
||||
$this->server->httpResponse->sendBody($dom->saveXML());
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
@ -678,9 +748,10 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
* An exception is thrown if it's not.
|
||||
*
|
||||
* @param resource|string $data
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
protected function validateICalendar(&$data) {
|
||||
protected function validateICalendar(&$data, $path) {
|
||||
|
||||
// If it's a stream, we convert it to a string first.
|
||||
if (is_resource($data)) {
|
||||
|
@ -704,6 +775,11 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
throw new Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support iCalendar objects.');
|
||||
}
|
||||
|
||||
// Get the Supported Components for the target calendar
|
||||
list($parentPath,$object) = Sabre_Dav_URLUtil::splitPath($path);
|
||||
$calendarProperties = $this->server->getProperties($parentPath,array('{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'));
|
||||
$supportedComponents = $calendarProperties['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue();
|
||||
|
||||
$foundType = null;
|
||||
$foundUID = null;
|
||||
foreach($vobj->getComponents() as $component) {
|
||||
|
@ -715,6 +791,9 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
case 'VJOURNAL' :
|
||||
if (is_null($foundType)) {
|
||||
$foundType = $component->name;
|
||||
if (!in_array($foundType, $supportedComponents)) {
|
||||
throw new Sabre_CalDAV_Exception_InvalidComponentType('This calendar only supports ' . implode(', ', $supportedComponents) . '. We found a ' . $foundType);
|
||||
}
|
||||
if (!isset($component->UID)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Every ' . $component->name . ' component must have an UID');
|
||||
}
|
||||
|
@ -756,7 +835,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
throw new Sabre_DAV_Exception_BadRequest('The Recipient: header must be specified when making POST requests');
|
||||
}
|
||||
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/', $originator)) {
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/i', $originator)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Originator must start with mailto: and must be valid email address');
|
||||
}
|
||||
$originator = substr($originator,7);
|
||||
|
@ -765,7 +844,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
foreach($recipients as $k=>$recipient) {
|
||||
|
||||
$recipient = trim($recipient);
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/', $recipient)) {
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/i', $recipient)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Recipients must start with mailto: and must be valid email address');
|
||||
}
|
||||
$recipient = substr($recipient, 7);
|
||||
|
@ -813,9 +892,10 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
}
|
||||
|
||||
if (in_array($method, array('REQUEST','REPLY','ADD','CANCEL')) && $componentType==='VEVENT') {
|
||||
$this->iMIPMessage($originator, $recipients, $vObject, $principal);
|
||||
$result = $this->iMIPMessage($originator, $recipients, $vObject, $principal);
|
||||
$this->server->httpResponse->sendStatus(200);
|
||||
$this->server->httpResponse->sendBody('Messages sent');
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml');
|
||||
$this->server->httpResponse->sendBody($this->generateScheduleResponse($result));
|
||||
} else {
|
||||
throw new Sabre_DAV_Exception_NotImplemented('This iTIP method is currently not implemented');
|
||||
}
|
||||
|
@ -825,18 +905,81 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
/**
|
||||
* Sends an iMIP message by email.
|
||||
*
|
||||
* This method must return an array with status codes per recipient.
|
||||
* This should look something like:
|
||||
*
|
||||
* array(
|
||||
* 'user1@example.org' => '2.0;Success'
|
||||
* )
|
||||
*
|
||||
* Formatting for this status code can be found at:
|
||||
* https://tools.ietf.org/html/rfc5545#section-3.8.8.3
|
||||
*
|
||||
* A list of valid status codes can be found at:
|
||||
* https://tools.ietf.org/html/rfc5546#section-3.6
|
||||
*
|
||||
* @param string $originator
|
||||
* @param array $recipients
|
||||
* @param Sabre_VObject_Component $vObject
|
||||
* @param string $principal Principal url
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
protected function iMIPMessage($originator, array $recipients, Sabre_VObject_Component $vObject, $principal) {
|
||||
|
||||
if (!$this->imipHandler) {
|
||||
throw new Sabre_DAV_Exception_NotImplemented('No iMIP handler is setup on this server.');
|
||||
}
|
||||
$resultStatus = '5.2;This server does not support this operation';
|
||||
} else {
|
||||
$this->imipHandler->sendMessage($originator, $recipients, $vObject, $principal);
|
||||
$resultStatus = '2.0;Success';
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach($recipients as $recipient) {
|
||||
$result[$recipient] = $resultStatus;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a schedule-response XML body
|
||||
*
|
||||
* The recipients array is a key->value list, containing email addresses
|
||||
* and iTip status codes. See the iMIPMessage method for a description of
|
||||
* the value.
|
||||
*
|
||||
* @param array $recipients
|
||||
* @return string
|
||||
*/
|
||||
public function generateScheduleResponse(array $recipients) {
|
||||
|
||||
$dom = new DOMDocument('1.0','utf-8');
|
||||
$dom->formatOutput = true;
|
||||
$xscheduleResponse = $dom->createElement('cal:schedule-response');
|
||||
$dom->appendChild($xscheduleResponse);
|
||||
|
||||
foreach($this->server->xmlNamespaces as $namespace=>$prefix) {
|
||||
|
||||
$xscheduleResponse->setAttribute('xmlns:' . $prefix, $namespace);
|
||||
|
||||
}
|
||||
|
||||
foreach($recipients as $recipient=>$status) {
|
||||
$xresponse = $dom->createElement('cal:response');
|
||||
|
||||
$xrecipient = $dom->createElement('cal:recipient');
|
||||
$xrecipient->appendChild($dom->createTextNode($recipient));
|
||||
$xresponse->appendChild($xrecipient);
|
||||
|
||||
$xrequestStatus = $dom->createElement('cal:request-status');
|
||||
$xrequestStatus->appendChild($dom->createTextNode($status));
|
||||
$xresponse->appendChild($xrequestStatus);
|
||||
|
||||
$xscheduleResponse->appendChild($xresponse);
|
||||
|
||||
}
|
||||
|
||||
return $dom->saveXML();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
|
|||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
* @var Sabre_CalDAV_Backend_BackendInterface
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
|
@ -36,10 +36,10 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
|
|||
* Constructor
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param Sabre_CalDAV_Backend_BackendInterface $caldavBackend
|
||||
* @param mixed $userUri
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_Abstract $caldavBackend, $userUri) {
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_BackendInterface $caldavBackend, $userUri) {
|
||||
|
||||
$this->principalBackend = $principalBackend;
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
|
@ -171,6 +171,11 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
|
|||
$objs[] = new Sabre_CalDAV_Calendar($this->principalBackend, $this->caldavBackend, $calendar);
|
||||
}
|
||||
$objs[] = new Sabre_CalDAV_Schedule_Outbox($this->principalInfo['uri']);
|
||||
|
||||
// We're adding a notifications node, if it's supported by the backend.
|
||||
if ($this->caldavBackend instanceof Sabre_CalDAV_Backend_NotificationSupport) {
|
||||
$objs[] = new Sabre_CalDAV_Notifications_Collection($this->caldavBackend, $this->principalInfo['uri']);
|
||||
}
|
||||
return $objs;
|
||||
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
|
|||
* Creates a new card.
|
||||
*
|
||||
* The addressbook id will be passed as the first argument. This is the
|
||||
* same id as it is returned from the getCards method.
|
||||
* same id as it is returned from the getAddressbooksForUser method.
|
||||
*
|
||||
* The cardUri is a base uri, and doesn't include the full path. The
|
||||
* cardData argument is the vcard body, and is passed as a string.
|
||||
|
|
|
@ -358,6 +358,10 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
throw new Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support vcard objects.');
|
||||
}
|
||||
|
||||
if (!isset($vobj->UID)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Every vcard must have an UID.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -440,6 +444,8 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
$vcard = Sabre_VObject_Reader::read($vcardData);
|
||||
|
||||
if (!$filters) return true;
|
||||
|
||||
foreach($filters as $filter) {
|
||||
|
||||
$isDefined = isset($vcard->{$filter['name']});
|
||||
|
|
|
@ -293,7 +293,10 @@ class Sabre_DAV_Locks_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
$this->server->tree->getNodeForPath($uri);
|
||||
|
||||
// We need to call the beforeWriteContent event for RFC3744
|
||||
$this->server->broadcastEvent('beforeWriteContent',array($uri));
|
||||
// Edit: looks like this is not used, and causing problems now.
|
||||
//
|
||||
// See Issue 222
|
||||
// $this->server->broadcastEvent('beforeWriteContent',array($uri));
|
||||
|
||||
} catch (Sabre_DAV_Exception_NotFound $e) {
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_Property {
|
||||
abstract class Sabre_DAV_Property implements Sabre_DAV_PropertyInterface {
|
||||
|
||||
abstract function serialize(Sabre_DAV_Server $server, DOMElement $prop);
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ class Sabre_DAV_Property_Response extends Sabre_DAV_Property implements Sabre_DA
|
|||
if (is_scalar($propertyValue)) {
|
||||
$text = $document->createTextNode($propertyValue);
|
||||
$currentProperty->appendChild($text);
|
||||
} elseif ($propertyValue instanceof Sabre_DAV_Property) {
|
||||
} elseif ($propertyValue instanceof Sabre_DAV_PropertyInterface) {
|
||||
$propertyValue->serialize($server,$currentProperty);
|
||||
} elseif (!is_null($propertyValue)) {
|
||||
throw new Sabre_DAV_Exception('Unknown property value type: ' . gettype($propertyValue) . ' for property: ' . $propertyName);
|
||||
|
|
21
dav/SabreDAV/lib/Sabre/DAV/PropertyInterface.php
Normal file
21
dav/SabreDAV/lib/Sabre/DAV/PropertyInterface.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PropertyInterface
|
||||
*
|
||||
* Implement this interface to create new complex properties
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_DAV_PropertyInterface {
|
||||
|
||||
public function serialize(Sabre_DAV_Server $server, DOMElement $prop);
|
||||
|
||||
static function unserialize(DOMElement $prop);
|
||||
|
||||
}
|
||||
|
|
@ -207,6 +207,10 @@ class Sabre_DAV_Server {
|
|||
|
||||
} catch (Exception $e) {
|
||||
|
||||
try {
|
||||
$this->broadcastEvent('exception', array($e));
|
||||
} catch (Exception $ignore) {
|
||||
}
|
||||
$DOM = new DOMDocument('1.0','utf-8');
|
||||
$DOM->formatOutput = true;
|
||||
|
||||
|
@ -508,7 +512,7 @@ class Sabre_DAV_Server {
|
|||
|
||||
if (!$this->checkPreconditions(true)) return false;
|
||||
|
||||
if (!($node instanceof Sabre_DAV_IFile)) throw new Sabre_DAV_Exception_NotImplemented('GET is only implemented on File objects');
|
||||
if (!$node instanceof Sabre_DAV_IFile) throw new Sabre_DAV_Exception_NotImplemented('GET is only implemented on File objects');
|
||||
$body = $node->get();
|
||||
|
||||
// Converting string into stream, if needed.
|
||||
|
|
|
@ -42,9 +42,9 @@ class Sabre_DAV_Tree_Filesystem extends Sabre_DAV_Tree {
|
|||
$realPath = $this->getRealPath($path);
|
||||
if (!file_exists($realPath)) throw new Sabre_DAV_Exception_NotFound('File at location ' . $realPath . ' not found');
|
||||
if (is_dir($realPath)) {
|
||||
return new Sabre_DAV_FS_Directory($path);
|
||||
return new Sabre_DAV_FS_Directory($realPath);
|
||||
} else {
|
||||
return new Sabre_DAV_FS_File($path);
|
||||
return new Sabre_DAV_FS_File($realPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
40
dav/SabreDAV/lib/Sabre/VObject/Property/DateTime.php
Executable file → Normal file
40
dav/SabreDAV/lib/Sabre/VObject/Property/DateTime.php
Executable file → Normal file
|
@ -204,49 +204,17 @@ class Sabre_VObject_Property_DateTime extends Sabre_VObject_Property {
|
|||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// tzid an Olson identifier?
|
||||
$tz = new DateTimeZone($tzid->value);
|
||||
} catch (Exception $e) {
|
||||
|
||||
// Not an Olson id, we're going to try to find the information
|
||||
// through the time zone name map.
|
||||
$newtzid = Sabre_VObject_WindowsTimezoneMap::lookup($tzid->value);
|
||||
if (is_null($newtzid)) {
|
||||
|
||||
// Not a well known time zone name either, we're going to try
|
||||
// to find the information through the VTIMEZONE object.
|
||||
|
||||
// First we find the root object
|
||||
// To look up the timezone, we must first find the VCALENDAR component.
|
||||
$root = $property;
|
||||
while($root->parent) {
|
||||
$root = $root->parent;
|
||||
}
|
||||
|
||||
if (isset($root->VTIMEZONE)) {
|
||||
foreach($root->VTIMEZONE as $vtimezone) {
|
||||
if (((string)$vtimezone->TZID) == $tzid) {
|
||||
if (isset($vtimezone->{'X-LIC-LOCATION'})) {
|
||||
$newtzid = (string)$vtimezone->{'X-LIC-LOCATION'};
|
||||
if ($root->name === 'VCALENDAR') {
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone((string)$tzid, $root);
|
||||
} else {
|
||||
// No libical location specified. As a last resort we could
|
||||
// try matching $vtimezone's DST rules against all known
|
||||
// time zones returned by DateTimeZone::list*
|
||||
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone((string)$tzid);
|
||||
}
|
||||
|
||||
try {
|
||||
$tz = new DateTimeZone($newtzid);
|
||||
} catch (Exception $e) {
|
||||
// If all else fails, we use the default PHP timezone
|
||||
$tz = new DateTimeZone(date_default_timezone_get());
|
||||
}
|
||||
}
|
||||
$dt = new DateTime($dateStr, $tz);
|
||||
$dt->setTimeZone($tz);
|
||||
|
||||
|
|
351
dav/SabreDAV/lib/Sabre/VObject/TimeZoneUtil.php
Normal file
351
dav/SabreDAV/lib/Sabre/VObject/TimeZoneUtil.php
Normal file
|
@ -0,0 +1,351 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Time zone name translation
|
||||
*
|
||||
* This file translates well-known time zone names into "Olson database" time zone names.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage VObject
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Frank Edelhaeuser (fedel@users.sourceforge.net)
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_VObject_TimeZoneUtil {
|
||||
|
||||
public static $map = array(
|
||||
|
||||
// from http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html
|
||||
// snapshot taken on 2012/01/16
|
||||
|
||||
// windows
|
||||
'AUS Central Standard Time'=>'Australia/Darwin',
|
||||
'AUS Eastern Standard Time'=>'Australia/Sydney',
|
||||
'Afghanistan Standard Time'=>'Asia/Kabul',
|
||||
'Alaskan Standard Time'=>'America/Anchorage',
|
||||
'Arab Standard Time'=>'Asia/Riyadh',
|
||||
'Arabian Standard Time'=>'Asia/Dubai',
|
||||
'Arabic Standard Time'=>'Asia/Baghdad',
|
||||
'Argentina Standard Time'=>'America/Buenos_Aires',
|
||||
'Armenian Standard Time'=>'Asia/Yerevan',
|
||||
'Atlantic Standard Time'=>'America/Halifax',
|
||||
'Azerbaijan Standard Time'=>'Asia/Baku',
|
||||
'Azores Standard Time'=>'Atlantic/Azores',
|
||||
'Bangladesh Standard Time'=>'Asia/Dhaka',
|
||||
'Canada Central Standard Time'=>'America/Regina',
|
||||
'Cape Verde Standard Time'=>'Atlantic/Cape_Verde',
|
||||
'Caucasus Standard Time'=>'Asia/Yerevan',
|
||||
'Cen. Australia Standard Time'=>'Australia/Adelaide',
|
||||
'Central America Standard Time'=>'America/Guatemala',
|
||||
'Central Asia Standard Time'=>'Asia/Almaty',
|
||||
'Central Brazilian Standard Time'=>'America/Cuiaba',
|
||||
'Central Europe Standard Time'=>'Europe/Budapest',
|
||||
'Central European Standard Time'=>'Europe/Warsaw',
|
||||
'Central Pacific Standard Time'=>'Pacific/Guadalcanal',
|
||||
'Central Standard Time'=>'America/Chicago',
|
||||
'Central Standard Time (Mexico)'=>'America/Mexico_City',
|
||||
'China Standard Time'=>'Asia/Shanghai',
|
||||
'Dateline Standard Time'=>'Etc/GMT+12',
|
||||
'E. Africa Standard Time'=>'Africa/Nairobi',
|
||||
'E. Australia Standard Time'=>'Australia/Brisbane',
|
||||
'E. Europe Standard Time'=>'Europe/Minsk',
|
||||
'E. South America Standard Time'=>'America/Sao_Paulo',
|
||||
'Eastern Standard Time'=>'America/New_York',
|
||||
'Egypt Standard Time'=>'Africa/Cairo',
|
||||
'Ekaterinburg Standard Time'=>'Asia/Yekaterinburg',
|
||||
'FLE Standard Time'=>'Europe/Kiev',
|
||||
'Fiji Standard Time'=>'Pacific/Fiji',
|
||||
'GMT Standard Time'=>'Europe/London',
|
||||
'GTB Standard Time'=>'Europe/Istanbul',
|
||||
'Georgian Standard Time'=>'Asia/Tbilisi',
|
||||
'Greenland Standard Time'=>'America/Godthab',
|
||||
'Greenwich Standard Time'=>'Atlantic/Reykjavik',
|
||||
'Hawaiian Standard Time'=>'Pacific/Honolulu',
|
||||
'India Standard Time'=>'Asia/Calcutta',
|
||||
'Iran Standard Time'=>'Asia/Tehran',
|
||||
'Israel Standard Time'=>'Asia/Jerusalem',
|
||||
'Jordan Standard Time'=>'Asia/Amman',
|
||||
'Kamchatka Standard Time'=>'Asia/Kamchatka',
|
||||
'Korea Standard Time'=>'Asia/Seoul',
|
||||
'Magadan Standard Time'=>'Asia/Magadan',
|
||||
'Mauritius Standard Time'=>'Indian/Mauritius',
|
||||
'Mexico Standard Time'=>'America/Mexico_City',
|
||||
'Mexico Standard Time 2'=>'America/Chihuahua',
|
||||
'Mid-Atlantic Standard Time'=>'Etc/GMT+2',
|
||||
'Middle East Standard Time'=>'Asia/Beirut',
|
||||
'Montevideo Standard Time'=>'America/Montevideo',
|
||||
'Morocco Standard Time'=>'Africa/Casablanca',
|
||||
'Mountain Standard Time'=>'America/Denver',
|
||||
'Mountain Standard Time (Mexico)'=>'America/Chihuahua',
|
||||
'Myanmar Standard Time'=>'Asia/Rangoon',
|
||||
'N. Central Asia Standard Time'=>'Asia/Novosibirsk',
|
||||
'Namibia Standard Time'=>'Africa/Windhoek',
|
||||
'Nepal Standard Time'=>'Asia/Katmandu',
|
||||
'New Zealand Standard Time'=>'Pacific/Auckland',
|
||||
'Newfoundland Standard Time'=>'America/St_Johns',
|
||||
'North Asia East Standard Time'=>'Asia/Irkutsk',
|
||||
'North Asia Standard Time'=>'Asia/Krasnoyarsk',
|
||||
'Pacific SA Standard Time'=>'America/Santiago',
|
||||
'Pacific Standard Time'=>'America/Los_Angeles',
|
||||
'Pacific Standard Time (Mexico)'=>'America/Santa_Isabel',
|
||||
'Pakistan Standard Time'=>'Asia/Karachi',
|
||||
'Paraguay Standard Time'=>'America/Asuncion',
|
||||
'Romance Standard Time'=>'Europe/Paris',
|
||||
'Russian Standard Time'=>'Europe/Moscow',
|
||||
'SA Eastern Standard Time'=>'America/Cayenne',
|
||||
'SA Pacific Standard Time'=>'America/Bogota',
|
||||
'SA Western Standard Time'=>'America/La_Paz',
|
||||
'SE Asia Standard Time'=>'Asia/Bangkok',
|
||||
'Samoa Standard Time'=>'Pacific/Apia',
|
||||
'Singapore Standard Time'=>'Asia/Singapore',
|
||||
'South Africa Standard Time'=>'Africa/Johannesburg',
|
||||
'Sri Lanka Standard Time'=>'Asia/Colombo',
|
||||
'Syria Standard Time'=>'Asia/Damascus',
|
||||
'Taipei Standard Time'=>'Asia/Taipei',
|
||||
'Tasmania Standard Time'=>'Australia/Hobart',
|
||||
'Tokyo Standard Time'=>'Asia/Tokyo',
|
||||
'Tonga Standard Time'=>'Pacific/Tongatapu',
|
||||
'US Eastern Standard Time'=>'America/Indianapolis',
|
||||
'US Mountain Standard Time'=>'America/Phoenix',
|
||||
'UTC'=>'Etc/GMT',
|
||||
'UTC+12'=>'Etc/GMT-12',
|
||||
'UTC-02'=>'Etc/GMT+2',
|
||||
'UTC-11'=>'Etc/GMT+11',
|
||||
'Ulaanbaatar Standard Time'=>'Asia/Ulaanbaatar',
|
||||
'Venezuela Standard Time'=>'America/Caracas',
|
||||
'Vladivostok Standard Time'=>'Asia/Vladivostok',
|
||||
'W. Australia Standard Time'=>'Australia/Perth',
|
||||
'W. Central Africa Standard Time'=>'Africa/Lagos',
|
||||
'W. Europe Standard Time'=>'Europe/Berlin',
|
||||
'West Asia Standard Time'=>'Asia/Tashkent',
|
||||
'West Pacific Standard Time'=>'Pacific/Port_Moresby',
|
||||
'Yakutsk Standard Time'=>'Asia/Yakutsk',
|
||||
|
||||
// Microsoft exchange timezones
|
||||
// Source:
|
||||
// http://msdn.microsoft.com/en-us/library/ms988620%28v=exchg.65%29.aspx
|
||||
//
|
||||
// Correct timezones deduced with help from:
|
||||
// http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
'Universal Coordinated Time' => 'UTC',
|
||||
'Casablanca, Monrovia' => 'Africa/Casablanca',
|
||||
'Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London' => 'Europe/Lisbon',
|
||||
'Greenwich Mean Time; Dublin, Edinburgh, London' => 'Europe/London',
|
||||
'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin',
|
||||
'Belgrade, Pozsony, Budapest, Ljubljana, Prague' => 'Europe/Prague',
|
||||
'Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris',
|
||||
'Paris, Madrid, Brussels, Copenhagen' => 'Europe/Paris',
|
||||
'Prague, Central Europe' => 'Europe/Prague',
|
||||
'Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb' => 'Europe/Sarajevo',
|
||||
'West Central Africa' => 'Africa/Luanda', // This was a best guess
|
||||
'Athens, Istanbul, Minsk' => 'Europe/Athens',
|
||||
'Bucharest' => 'Europe/Bucharest',
|
||||
'Cairo' => 'Africa/Cairo',
|
||||
'Harare, Pretoria' => 'Africa/Harare',
|
||||
'Helsinki, Riga, Tallinn' => 'Europe/Helsinki',
|
||||
'Israel, Jerusalem Standard Time' => 'Asia/Jerusalem',
|
||||
'Baghdad' => 'Asia/Baghdad',
|
||||
'Arab, Kuwait, Riyadh' => 'Asia/Kuwait',
|
||||
'Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow',
|
||||
'East Africa, Nairobi' => 'Africa/Nairobi',
|
||||
'Tehran' => 'Asia/Tehran',
|
||||
'Abu Dhabi, Muscat' => 'Asia/Muscat', // Best guess
|
||||
'Baku, Tbilisi, Yerevan' => 'Asia/Baku',
|
||||
'Kabul' => 'Asia/Kabul',
|
||||
'Ekaterinburg' => 'Asia/Yekaterinburg',
|
||||
'Islamabad, Karachi, Tashkent' => 'Asia/Karachi',
|
||||
'Kolkata, Chennai, Mumbai, New Delhi, India Standard Time' => 'Asia/Calcutta',
|
||||
'Kathmandu, Nepal' => 'Asia/Kathmandu',
|
||||
'Almaty, Novosibirsk, North Central Asia' => 'Asia/Almaty',
|
||||
'Astana, Dhaka' => 'Asia/Dhaka',
|
||||
'Sri Jayawardenepura, Sri Lanka' => 'Asia/Colombo',
|
||||
'Rangoon' => 'Asia/Rangoon',
|
||||
'Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok',
|
||||
'Krasnoyarsk' => 'Asia/Krasnoyarsk',
|
||||
'Beijing, Chongqing, Hong Kong SAR, Urumqi' => 'Asia/Shanghai',
|
||||
'Irkutsk, Ulaan Bataar' => 'Asia/Irkutsk',
|
||||
'Kuala Lumpur, Singapore' => 'Asia/Singapore',
|
||||
'Perth, Western Australia' => 'Australia/Perth',
|
||||
'Taipei' => 'Asia/Taipei',
|
||||
'Osaka, Sapporo, Tokyo' => 'Asia/Tokyo',
|
||||
'Seoul, Korea Standard time' => 'Asia/Seoul',
|
||||
'Yakutsk' => 'Asia/Yakutsk',
|
||||
'Adelaide, Central Australia' => 'Australia/Adelaide',
|
||||
'Darwin' => 'Australia/Darwin',
|
||||
'Brisbane, East Australia' => 'Australia/Brisbane',
|
||||
'Canberra, Melbourne, Sydney, Hobart (year 2000 only)' => 'Australia/Sydney',
|
||||
'Guam, Port Moresby' => 'Pacific/Guam',
|
||||
'Hobart, Tasmania' => 'Australia/Hobart',
|
||||
'Vladivostok' => 'Asia/Vladivostok',
|
||||
'Magadan, Solomon Is., New Caledonia' => 'Asia/Magadan',
|
||||
'Auckland, Wellington' => 'Pacific/Auckland',
|
||||
'Fiji Islands, Kamchatka, Marshall Is.' => 'Pacific/Fiji',
|
||||
'Nuku\'alofa, Tonga' => 'Pacific/Tongatapu',
|
||||
'Azores' => 'Atlantic/Azores',
|
||||
'Cape Verde Is.' => 'Atlantic/Cape_Verde',
|
||||
'Mid-Atlantic' => 'America/Noronha',
|
||||
'Brasilia' => 'America/Sao_Paulo', // Best guess
|
||||
'Buenos Aires' => 'America/Argentina/Buenos_Aires',
|
||||
'Greenland' => 'America/Godthab',
|
||||
'Newfoundland' => 'America/St_Johns',
|
||||
'Atlantic Time (Canada)' => 'America/Halifax',
|
||||
'Caracas, La Paz' => 'America/Caracas',
|
||||
'Santiago' => 'America/Santiago',
|
||||
'Bogota, Lima, Quito' => 'America/Bogota',
|
||||
'Eastern Time (US & Canada)' => 'America/New_York',
|
||||
'Indiana (East)' => 'America/Indiana/Indianapolis',
|
||||
'Central America' => 'America/Guatemala',
|
||||
'Central Time (US & Canada)' => 'America/Chicago',
|
||||
'Mexico City, Tegucigalpa' => 'America/Mexico_City',
|
||||
'Saskatchewan' => 'America/Edmonton',
|
||||
'Arizona' => 'America/Phoenix',
|
||||
'Mountain Time (US & Canada)' => 'America/Denver', // Best guess
|
||||
'Pacific Time (US & Canada); Tijuana' => 'America/Los_Angeles', // Best guess
|
||||
'Alaska' => 'America/Anchorage',
|
||||
'Hawaii' => 'Pacific/Honolulu',
|
||||
'Midway Island, Samoa' => 'Pacific/Midway',
|
||||
'Eniwetok, Kwajalein, Dateline Time' => 'Pacific/Kwajalein',
|
||||
|
||||
);
|
||||
|
||||
public static $microsoftExchangeMap = array(
|
||||
0 => 'UTC',
|
||||
31 => 'Africa/Casablanca',
|
||||
2 => 'Europe/Lisbon',
|
||||
1 => 'Europe/London',
|
||||
4 => 'Europe/Berlin',
|
||||
6 => 'Europe/Prague',
|
||||
3 => 'Europe/Paris',
|
||||
69 => 'Africa/Luanda', // This was a best guess
|
||||
7 => 'Europe/Athens',
|
||||
5 => 'Europe/Bucharest',
|
||||
49 => 'Africa/Cairo',
|
||||
50 => 'Africa/Harare',
|
||||
59 => 'Europe/Helsinki',
|
||||
27 => 'Asia/Jerusalem',
|
||||
26 => 'Asia/Baghdad',
|
||||
74 => 'Asia/Kuwait',
|
||||
51 => 'Europe/Moscow',
|
||||
56 => 'Africa/Nairobi',
|
||||
25 => 'Asia/Tehran',
|
||||
24 => 'Asia/Muscat', // Best guess
|
||||
54 => 'Asia/Baku',
|
||||
48 => 'Asia/Kabul',
|
||||
58 => 'Asia/Yekaterinburg',
|
||||
47 => 'Asia/Karachi',
|
||||
23 => 'Asia/Calcutta',
|
||||
62 => 'Asia/Kathmandu',
|
||||
46 => 'Asia/Almaty',
|
||||
71 => 'Asia/Dhaka',
|
||||
66 => 'Asia/Colombo',
|
||||
61 => 'Asia/Rangoon',
|
||||
22 => 'Asia/Bangkok',
|
||||
64 => 'Asia/Krasnoyarsk',
|
||||
45 => 'Asia/Shanghai',
|
||||
63 => 'Asia/Irkutsk',
|
||||
21 => 'Asia/Singapore',
|
||||
73 => 'Australia/Perth',
|
||||
75 => 'Asia/Taipei',
|
||||
20 => 'Asia/Tokyo',
|
||||
72 => 'Asia/Seoul',
|
||||
70 => 'Asia/Yakutsk',
|
||||
19 => 'Australia/Adelaide',
|
||||
44 => 'Australia/Darwin',
|
||||
18 => 'Australia/Brisbane',
|
||||
76 => 'Australia/Sydney',
|
||||
43 => 'Pacific/Guam',
|
||||
42 => 'Australia/Hobart',
|
||||
68 => 'Asia/Vladivostok',
|
||||
41 => 'Asia/Magadan',
|
||||
17 => 'Pacific/Auckland',
|
||||
40 => 'Pacific/Fiji',
|
||||
67 => 'Pacific/Tongatapu',
|
||||
29 => 'Atlantic/Azores',
|
||||
53 => 'Atlantic/Cape_Verde',
|
||||
30 => 'America/Noronha',
|
||||
8 => 'America/Sao_Paulo', // Best guess
|
||||
32 => 'America/Argentina/Buenos_Aires',
|
||||
69 => 'America/Godthab',
|
||||
28 => 'America/St_Johns',
|
||||
9 => 'America/Halifax',
|
||||
33 => 'America/Caracas',
|
||||
65 => 'America/Santiago',
|
||||
35 => 'America/Bogota',
|
||||
10 => 'America/New_York',
|
||||
34 => 'America/Indiana/Indianapolis',
|
||||
55 => 'America/Guatemala',
|
||||
11 => 'America/Chicago',
|
||||
37 => 'America/Mexico_City',
|
||||
36 => 'America/Edmonton',
|
||||
38 => 'America/Phoenix',
|
||||
12 => 'America/Denver', // Best guess
|
||||
13 => 'America/Los_Angeles', // Best guess
|
||||
14 => 'America/Anchorage',
|
||||
15 => 'Pacific/Honolulu',
|
||||
16 => 'Pacific/Midway',
|
||||
39 => 'Pacific/Kwajalein',
|
||||
);
|
||||
|
||||
/**
|
||||
* This method will try to find out the correct timezone for an iCalendar
|
||||
* date-time value.
|
||||
*
|
||||
* You must pass the contents of the TZID parameter, as well as the full
|
||||
* calendar.
|
||||
*
|
||||
* If the lookup fails, this method will return UTC.
|
||||
*
|
||||
* @param string $tzid
|
||||
* @param Sabre_VObject_Component $vcalendar
|
||||
* @return DateTimeZone
|
||||
*/
|
||||
static public function getTimeZone($tzid, Sabre_VObject_Component $vcalendar = null) {
|
||||
|
||||
// First we will just see if the tzid is a support timezone identifier.
|
||||
try {
|
||||
return new DateTimeZone($tzid);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
// Next, we check if the tzid is somewhere in our tzid map.
|
||||
if (isset(self::$map[$tzid])) {
|
||||
return new DateTimeZone(self::$map[$tzid]);
|
||||
}
|
||||
|
||||
if ($vcalendar) {
|
||||
|
||||
// If that didn't work, we will scan VTIMEZONE objects
|
||||
foreach($vcalendar->select('VTIMEZONE') as $vtimezone) {
|
||||
|
||||
if ((string)$vtimezone->TZID === $tzid) {
|
||||
|
||||
// Some clients add 'X-LIC-LOCATION' with the olson name.
|
||||
if (isset($vtimezone->{'X-LIC-LOCATION'})) {
|
||||
try {
|
||||
return new DateTimeZone($vtimezone->{'X-LIC-LOCATION'});
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
}
|
||||
// Microsoft may add a magic number, which we also have an
|
||||
// answer for.
|
||||
if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
|
||||
if (isset(self::$microsoftExchangeMap[(int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value])) {
|
||||
return new DateTimeZone(self::$microsoftExchangeMap[(int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If we got all the way here, we default to UTC.
|
||||
return new DateTimeZone(date_default_timezone_get());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -24,8 +24,8 @@ include __DIR__ . '/Parameter.php';
|
|||
include __DIR__ . '/ParseException.php';
|
||||
include __DIR__ . '/Reader.php';
|
||||
include __DIR__ . '/RecurrenceIterator.php';
|
||||
include __DIR__ . '/TimeZoneUtil.php';
|
||||
include __DIR__ . '/Version.php';
|
||||
include __DIR__ . '/WindowsTimezoneMap.php';
|
||||
include __DIR__ . '/Element.php';
|
||||
include __DIR__ . '/Property.php';
|
||||
include __DIR__ . '/Component.php';
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract {
|
||||
class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract implements Sabre_CalDAV_Backend_NotificationSupport {
|
||||
|
||||
private $calendarData;
|
||||
private $calendars;
|
||||
private $notifications;
|
||||
|
||||
function __construct(array $calendars, array $calendarData) {
|
||||
function __construct(array $calendars, array $calendarData, array $notifications = array()) {
|
||||
|
||||
$this->calendars = $calendars;
|
||||
$this->calendarData = $calendarData;
|
||||
$this->notifications = $notifications;
|
||||
|
||||
}
|
||||
|
||||
|
@ -58,7 +60,15 @@ class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract {
|
|||
*/
|
||||
function createCalendar($principalUri,$calendarUri,array $properties) {
|
||||
|
||||
throw new Exception('Not implemented');
|
||||
$id = Sabre_DAV_UUIDUtil::getUUID();
|
||||
$this->calendars[] = array_merge(array(
|
||||
'id' => $id,
|
||||
'principaluri' => $principalUri,
|
||||
'uri' => $calendarUri,
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet(array('VEVENT','VTODO')),
|
||||
), $properties);
|
||||
|
||||
return $id;
|
||||
|
||||
}
|
||||
|
||||
|
@ -112,7 +122,11 @@ class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract {
|
|||
*/
|
||||
public function deleteCalendar($calendarId) {
|
||||
|
||||
throw new Exception('Not implemented');
|
||||
foreach($this->calendars as $k=>$calendar) {
|
||||
if ($calendar['id'] === $calendarId) {
|
||||
unset($this->calendars[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -227,4 +241,37 @@ class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of notifications for a given principal url.
|
||||
*
|
||||
* The returned array should only consist of implementations of
|
||||
* Sabre_CalDAV_Notifications_INotificationType.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getNotificationsForPrincipal($principalUri) {
|
||||
|
||||
if (isset($this->notifications[$principalUri])) {
|
||||
return $this->notifications[$principalUri];
|
||||
}
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This deletes a specific notifcation.
|
||||
*
|
||||
* This may be called by a client once it deems a notification handled.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param Sabre_CalDAV_Notifications_INotificationType $notification
|
||||
* @return void
|
||||
*/
|
||||
public function deleteNotification($principalUri, Sabre_CalDAV_Notifications_INotificationType $notification) {
|
||||
|
||||
throw new Sabre_DAV_Exception_NotImplemented('This doesn\'t work!');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,6 +55,56 @@ class Sabre_CalDAV_ICSExportPluginTest extends PHPUnit_Framework_TestCase {
|
|||
$this->assertEquals(1,count($obj->VERSION));
|
||||
$this->assertEquals(1,count($obj->CALSCALE));
|
||||
$this->assertEquals(1,count($obj->PRODID));
|
||||
$this->assertTrue(strpos((string)$obj->PRODID, Sabre_DAV_Version::VERSION)!==false);
|
||||
$this->assertEquals(1,count($obj->VTIMEZONE));
|
||||
$this->assertEquals(1,count($obj->VEVENT));
|
||||
|
||||
}
|
||||
function testBeforeMethodNoVersion() {
|
||||
|
||||
if (!SABRE_HASSQLITE) $this->markTestSkipped('SQLite driver is not available');
|
||||
$cbackend = Sabre_CalDAV_TestUtil::getBackend();
|
||||
$pbackend = new Sabre_DAVACL_MockPrincipalBackend();
|
||||
|
||||
$props = array(
|
||||
'uri'=>'UUID-123467',
|
||||
'principaluri' => 'admin',
|
||||
'id' => 1,
|
||||
);
|
||||
$tree = array(
|
||||
new Sabre_CalDAV_Calendar($pbackend,$cbackend,$props),
|
||||
);
|
||||
|
||||
$p = new Sabre_CalDAV_ICSExportPlugin();
|
||||
|
||||
$s = new Sabre_DAV_Server($tree);
|
||||
|
||||
$s->addPlugin($p);
|
||||
$s->addPlugin(new Sabre_CalDAV_Plugin());
|
||||
|
||||
$h = new Sabre_HTTP_Request(array(
|
||||
'QUERY_STRING' => 'export',
|
||||
));
|
||||
|
||||
$s->httpRequest = $h;
|
||||
$s->httpResponse = new Sabre_HTTP_ResponseMock();
|
||||
|
||||
Sabre_DAV_Server::$exposeVersion = false;
|
||||
$this->assertFalse($p->beforeMethod('GET','UUID-123467?export'));
|
||||
Sabre_DAV_Server::$exposeVersion = true;
|
||||
|
||||
$this->assertEquals('HTTP/1.1 200 OK',$s->httpResponse->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'text/calendar',
|
||||
), $s->httpResponse->headers);
|
||||
|
||||
$obj = Sabre_VObject_Reader::read($s->httpResponse->body);
|
||||
|
||||
$this->assertEquals(5,count($obj->children()));
|
||||
$this->assertEquals(1,count($obj->VERSION));
|
||||
$this->assertEquals(1,count($obj->CALSCALE));
|
||||
$this->assertEquals(1,count($obj->PRODID));
|
||||
$this->assertFalse(strpos((string)$obj->PRODID, Sabre_DAV_Version::VERSION)!==false);
|
||||
$this->assertEquals(1,count($obj->VTIMEZONE));
|
||||
$this->assertEquals(1,count($obj->VEVENT));
|
||||
|
||||
|
|
96
dav/SabreDAV/tests/Sabre/CalDAV/Issue220Test.php
Normal file
96
dav/SabreDAV/tests/Sabre/CalDAV/Issue220Test.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This unittest is created to check for an endless loop in Sabre_CalDAV_CalendarQueryValidator
|
||||
*
|
||||
*
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Issue220Test extends Sabre_DAVServerTest {
|
||||
|
||||
protected $setupCalDAV = true;
|
||||
|
||||
protected $caldavCalendars = array(
|
||||
array(
|
||||
'id' => 1,
|
||||
'name' => 'Calendar',
|
||||
'principaluri' => 'principals/user1',
|
||||
'uri' => 'calendar1',
|
||||
)
|
||||
);
|
||||
|
||||
protected $caldavCalendarObjects = array(
|
||||
1 => array(
|
||||
'event.ics' => array(
|
||||
'calendardata' => 'BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=Europe/Berlin:20120601T180000
|
||||
SUMMARY:Brot backen
|
||||
RRULE:FREQ=DAILY;INTERVAL=1;WKST=MO
|
||||
TRANSP:OPAQUE
|
||||
DURATION:PT20M
|
||||
LAST-MODIFIED:20120601T064634Z
|
||||
CREATED:20120601T064634Z
|
||||
DTSTAMP:20120601T064634Z
|
||||
UID:b64f14c5-dccc-4eda-947f-bdb1f763fbcd
|
||||
BEGIN:VALARM
|
||||
TRIGGER;VALUE=DURATION:-PT5M
|
||||
ACTION:DISPLAY
|
||||
DESCRIPTION:Default Event Notification
|
||||
X-WR-ALARMUID:cd952c1b-b3d6-41fb-b0a6-ec3a1a5bdd58
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=Europe/Berlin:20120606T180000
|
||||
SUMMARY:Brot backen
|
||||
TRANSP:OPAQUE
|
||||
STATUS:CANCELLED
|
||||
DTEND;TZID=Europe/Berlin:20120606T182000
|
||||
LAST-MODIFIED:20120605T094310Z
|
||||
SEQUENCE:1
|
||||
RECURRENCE-ID:20120606T160000Z
|
||||
UID:b64f14c5-dccc-4eda-947f-bdb1f763fbcd
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
function testIssue220() {
|
||||
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'REPORT',
|
||||
'HTTP_CONTENT_TYPE' => 'application/xml',
|
||||
'REQUEST_URI' => '/calendars/user1/calendar1',
|
||||
'HTTP_DEPTH' => '1',
|
||||
));
|
||||
|
||||
$request->setBody('<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<D:prop>
|
||||
<C:calendar-data/>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
<C:filter>
|
||||
<C:comp-filter name="VCALENDAR">
|
||||
<C:comp-filter name="VEVENT">
|
||||
<C:comp-filter name="VALARM">
|
||||
<C:time-range start="20120607T161646Z" end="20120612T161646Z"/>
|
||||
</C:comp-filter>
|
||||
</C:comp-filter>
|
||||
</C:comp-filter>
|
||||
</C:filter>
|
||||
</C:calendar-query>');
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertFalse(strpos($response->body, '<s:exception>PHPUnit_Framework_Error_Warning</s:exception>'), 'Error Warning occurred: ' . $response->body);
|
||||
$this->assertFalse(strpos($response->body, 'Invalid argument supplied for foreach()'), 'Invalid argument supplied for foreach(): ' . $response->body);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Notifications_CollectionTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testGetChildren() {
|
||||
|
||||
$principalUri = 'principals/user1';
|
||||
|
||||
$systemStatus = new Sabre_CalDAV_Notifications_Notification_SystemStatus(1);
|
||||
|
||||
$caldavBackend = new Sabre_CalDAV_Backend_Mock(array(),array(), array(
|
||||
'principals/user1' => array(
|
||||
$systemStatus
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
$col = new Sabre_CalDAV_Notifications_Collection($caldavBackend, $principalUri);
|
||||
$this->assertEquals('notifications', $col->getName());
|
||||
|
||||
$this->assertEquals(array(
|
||||
new Sabre_CalDAV_Notifications_Node($caldavBackend, $systemStatus)
|
||||
), $col->getChildren());
|
||||
|
||||
}
|
||||
|
||||
}
|
23
dav/SabreDAV/tests/Sabre/CalDAV/Notifications/NodeTest.php
Normal file
23
dav/SabreDAV/tests/Sabre/CalDAV/Notifications/NodeTest.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Notifications_NodeTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testGetId() {
|
||||
|
||||
$principalUri = 'principals/user1';
|
||||
|
||||
$systemStatus = new Sabre_CalDAV_Notifications_Notification_SystemStatus(1);
|
||||
|
||||
$caldavBackend = new Sabre_CalDAV_Backend_Mock(array(),array(), array(
|
||||
'principals/user1' => array(
|
||||
$systemStatus
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
$node = new Sabre_CalDAV_Notifications_Node($caldavBackend, $systemStatus);
|
||||
$this->assertEquals($systemStatus->getId(), $node->getName());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Notifications_Notification extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
function testSerializers($notification, $expected1, $expected2) {
|
||||
|
||||
$this->assertEquals('foo', $notification->getId());
|
||||
|
||||
|
||||
$dom = new DOMDocument('1.0','UTF-8');
|
||||
$elem = $dom->createElement('cs:root');
|
||||
$elem->setAttribute('xmlns:cs',Sabre_CalDAV_Plugin::NS_CALENDARSERVER);
|
||||
$dom->appendChild($elem);
|
||||
$notification->serialize(new Sabre_DAV_Server(), $elem);
|
||||
$this->assertEquals($expected1, $dom->saveXML());
|
||||
|
||||
$dom = new DOMDocument('1.0','UTF-8');
|
||||
$elem = $dom->createElement('cs:root');
|
||||
$elem->setAttribute('xmlns:cs',Sabre_CalDAV_Plugin::NS_CALENDARSERVER);
|
||||
$dom->appendChild($elem);
|
||||
$notification->serializeBody(new Sabre_DAV_Server(), $elem);
|
||||
$this->assertEquals($expected2, $dom->saveXML());
|
||||
|
||||
|
||||
}
|
||||
|
||||
function dataProvider() {
|
||||
|
||||
return array(
|
||||
|
||||
array(
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo'),
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="high"/></cs:root>' . "\n",
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="high"/></cs:root>' . "\n",
|
||||
),
|
||||
|
||||
array(
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo',Sabre_CalDAV_Notifications_Notification_SystemStatus::TYPE_MEDIUM,'bar'),
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="medium"/></cs:root>' . "\n",
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="medium"><cs:description>bar</cs:description></cs:systemstatus></cs:root>' . "\n",
|
||||
),
|
||||
|
||||
array(
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo',Sabre_CalDAV_Notifications_Notification_SystemStatus::TYPE_LOW,null,'http://example.org/'),
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="low"/></cs:root>' . "\n",
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="low"><d:href>http://example.org/</d:href></cs:systemstatus></cs:root>' . "\n",
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -191,7 +191,17 @@ class Sabre_CalDAV_OutboxPostTest extends Sabre_DAVServerTest {
|
|||
|
||||
$req->setBody(implode("\r\n",$body));
|
||||
|
||||
$this->assertHTTPStatus(501, $req);
|
||||
|
||||
$response = $this->request($req);
|
||||
$this->assertEquals('HTTP/1.1 200 OK', $response->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'application/xml',
|
||||
), $response->headers);
|
||||
|
||||
// Lazily checking the body for a few expected values.
|
||||
$this->assertTrue(strpos($response->body, '5.2;')!==false);
|
||||
$this->assertTrue(strpos($response->body,'user2@example.org')!==false);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -218,7 +228,66 @@ class Sabre_CalDAV_OutboxPostTest extends Sabre_DAVServerTest {
|
|||
$handler = new Sabre_CalDAV_Schedule_IMip_Mock('server@example.org');
|
||||
|
||||
$this->caldavPlugin->setIMIPhandler($handler);
|
||||
$this->assertHTTPStatus(200, $req);
|
||||
|
||||
$response = $this->request($req);
|
||||
$this->assertEquals('HTTP/1.1 200 OK', $response->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'application/xml',
|
||||
), $response->headers);
|
||||
|
||||
// Lazily checking the body for a few expected values.
|
||||
$this->assertTrue(strpos($response->body, '2.0;')!==false);
|
||||
$this->assertTrue(strpos($response->body,'user2@example.org')!==false);
|
||||
|
||||
$this->assertEquals(array(
|
||||
array(
|
||||
'to' => 'user2@example.org',
|
||||
'subject' => 'Invitation for: An invitation',
|
||||
'body' => implode("\r\n", $body) . "\r\n",
|
||||
'headers' => array(
|
||||
'Reply-To: user1.sabredav@sabredav.org',
|
||||
'From: server@example.org',
|
||||
'Content-Type: text/calendar; method=REQUEST; charset=utf-8',
|
||||
'X-Sabre-Version: ' . Sabre_DAV_Version::VERSION . '-' . Sabre_DAV_Version::STABILITY,
|
||||
),
|
||||
)
|
||||
), $handler->getSentEmails());
|
||||
|
||||
}
|
||||
|
||||
function testSuccessRequestUpperCased() {
|
||||
|
||||
$req = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'POST',
|
||||
'REQUEST_URI' => '/calendars/user1/outbox',
|
||||
'HTTP_ORIGINATOR' => 'MAILTO:user1.sabredav@sabredav.org',
|
||||
'HTTP_RECIPIENT' => 'MAILTO:user2@example.org',
|
||||
));
|
||||
|
||||
$body = array(
|
||||
'BEGIN:VCALENDAR',
|
||||
'METHOD:REQUEST',
|
||||
'BEGIN:VEVENT',
|
||||
'SUMMARY:An invitation',
|
||||
'END:VEVENT',
|
||||
'END:VCALENDAR',
|
||||
);
|
||||
|
||||
$req->setBody(implode("\r\n",$body));
|
||||
|
||||
$handler = new Sabre_CalDAV_Schedule_IMip_Mock('server@example.org');
|
||||
|
||||
$this->caldavPlugin->setIMIPhandler($handler);
|
||||
|
||||
$response = $this->request($req);
|
||||
$this->assertEquals('HTTP/1.1 200 OK', $response->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'application/xml',
|
||||
), $response->headers);
|
||||
|
||||
// Lazily checking the body for a few expected values.
|
||||
$this->assertTrue(strpos($response->body, '2.0;')!==false);
|
||||
$this->assertTrue(strpos($response->body,'user2@example.org')!==false);
|
||||
|
||||
$this->assertEquals(array(
|
||||
array(
|
||||
|
|
|
@ -23,8 +23,34 @@ class Sabre_CalDAV_PluginTest extends PHPUnit_Framework_TestCase {
|
|||
|
||||
function setup() {
|
||||
|
||||
if (!SABRE_HASSQLITE) $this->markTestSkipped('No PDO SQLite support');
|
||||
$this->caldavBackend = Sabre_CalDAV_TestUtil::getBackend();
|
||||
$this->caldavBackend = new Sabre_CalDAV_Backend_Mock(array(
|
||||
array(
|
||||
'id' => 1,
|
||||
'uri' => 'UUID-123467',
|
||||
'principaluri' => 'principals/user1',
|
||||
'{DAV:}displayname' => 'user1 calendar',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description',
|
||||
'{http://apple.com/ns/ical/}calendar-order' => '1',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet(array('VEVENT','VTODO')),
|
||||
),
|
||||
array(
|
||||
'id' => 2,
|
||||
'uri' => 'UUID-123468',
|
||||
'principaluri' => 'principals/user1',
|
||||
'{DAV:}displayname' => 'user1 calendar2',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description',
|
||||
'{http://apple.com/ns/ical/}calendar-order' => '1',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet(array('VEVENT','VTODO')),
|
||||
)
|
||||
), array(
|
||||
1 => array(
|
||||
'UUID-2345' => array(
|
||||
'calendardata' => Sabre_CalDAV_TestUtil::getTestCalendarData(),
|
||||
)
|
||||
)
|
||||
));
|
||||
$principalBackend = new Sabre_DAVACL_MockPrincipalBackend();
|
||||
$principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-read',array('principals/user1'));
|
||||
$principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-write',array('principals/user1'));
|
||||
|
@ -398,6 +424,7 @@ END:VCALENDAR';
|
|||
'{urn:ietf:params:xml:ns:caldav}calendar-user-address-set',
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}calendar-proxy-read-for',
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}calendar-proxy-write-for',
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}notification-URL',
|
||||
));
|
||||
|
||||
$this->assertArrayHasKey(0,$props);
|
||||
|
@ -414,6 +441,12 @@ END:VCALENDAR';
|
|||
$this->assertTrue($prop instanceof Sabre_DAV_Property_Href);
|
||||
$this->assertEquals('calendars/user1/outbox',$prop->getHref());
|
||||
|
||||
$this->assertArrayHasKey('{'.Sabre_CalDAV_Plugin::NS_CALENDARSERVER .'}notification-URL',$props[0][200]);
|
||||
$prop = $props[0][200]['{'.Sabre_CalDAV_Plugin::NS_CALENDARSERVER .'}notification-URL'];
|
||||
$this->assertTrue($prop instanceof Sabre_DAV_Property_Href);
|
||||
$this->assertEquals('calendars/user1/notifications/',$prop->getHref());
|
||||
|
||||
|
||||
$this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-address-set',$props[0][200]);
|
||||
$prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set'];
|
||||
$this->assertTrue($prop instanceof Sabre_DAV_Property_HrefList);
|
||||
|
@ -429,6 +462,7 @@ END:VCALENDAR';
|
|||
$this->assertInstanceOf('Sabre_DAV_Property_HrefList', $prop);
|
||||
$this->assertEquals(array('principals/admin'), $prop->getHrefs());
|
||||
|
||||
|
||||
}
|
||||
|
||||
function testSupportedReportSetPropertyNonCalendar() {
|
||||
|
@ -991,4 +1025,60 @@ END:VCALENDAR';
|
|||
$this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
|
||||
|
||||
}
|
||||
|
||||
function testNotificationProperties() {
|
||||
|
||||
$request = array(
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}notificationtype',
|
||||
);
|
||||
$result = array();
|
||||
$notification = new Sabre_CalDAV_Notifications_Node(
|
||||
$this->caldavBackend,
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo')
|
||||
);
|
||||
$this->plugin->beforeGetProperties('foo', $notification, $request, $result);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
200 => array(
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}notificationtype' => $notification->getNotificationType()
|
||||
)
|
||||
), $result);
|
||||
|
||||
}
|
||||
|
||||
function testNotificationGet() {
|
||||
|
||||
$notification = new Sabre_CalDAV_Notifications_Node(
|
||||
$this->caldavBackend,
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo')
|
||||
);
|
||||
|
||||
$server = new Sabre_DAV_Server(array($notification));
|
||||
$caldav = new Sabre_CalDAV_Plugin();
|
||||
|
||||
$httpResponse = new Sabre_HTTP_ResponseMock();
|
||||
$server->httpResponse = $httpResponse;
|
||||
|
||||
$server->addPlugin($caldav);
|
||||
|
||||
$caldav->beforeMethod('GET','foo');
|
||||
|
||||
$this->assertEquals('HTTP/1.1 200 OK', $httpResponse->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'application/xml',
|
||||
), $httpResponse->headers);
|
||||
|
||||
$expected =
|
||||
'<?xml version="1.0" encoding="UTF-8"?>
|
||||
<cs:notification xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
|
||||
<cs:systemstatus type="high"/>
|
||||
</cs:notification>
|
||||
';
|
||||
|
||||
$this->assertEquals($expected, $httpResponse->body);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,13 @@ class Sabre_CalDAV_ValidateICalTest extends PHPUnit_Framework_TestCase {
|
|||
'id' => 'calendar1',
|
||||
'principaluri' => 'principals/admin',
|
||||
'uri' => 'calendar1',
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet( array('VEVENT','VTODO','VJOURNAL') ),
|
||||
),
|
||||
array(
|
||||
'id' => 'calendar2',
|
||||
'principaluri' => 'principals/admin',
|
||||
'uri' => 'calendar2',
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet( array('VTODO','VJOURNAL') ),
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -207,4 +214,33 @@ class Sabre_CalDAV_ValidateICalTest extends PHPUnit_Framework_TestCase {
|
|||
$this->assertEquals($expected, $this->calBackend->getCalendarObject('calendar1','blabla.ics'));
|
||||
|
||||
}
|
||||
|
||||
function testCreateFileInvalidComponent() {
|
||||
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/calendars/admin/calendar2/blabla.ics',
|
||||
));
|
||||
$request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n");
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 403 Forbidden', $response->status, 'Incorrect status returned! Full response body: ' . $response->body);
|
||||
|
||||
}
|
||||
|
||||
function testUpdateFileInvalidComponent() {
|
||||
|
||||
$this->calBackend->createCalendarObject('calendar2','blabla.ics','foo');
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/calendars/admin/calendar2/blabla.ics',
|
||||
));
|
||||
$request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n");
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 403 Forbidden', $response->status, 'Incorrect status returned! Full response body: ' . $response->body);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,20 +65,35 @@ class Sabre_CardDAV_ValidateVCardTest extends PHPUnit_Framework_TestCase {
|
|||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf',
|
||||
));
|
||||
$request->setBody("BEGIN:VCARD\r\nEND:VCARD\r\n");
|
||||
$request->setBody("BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n");
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 201 Created', $response->status, 'Incorrect status returned! Full response body: ' . $response->body);
|
||||
$expected = array(
|
||||
'uri' => 'blabla.vcf',
|
||||
'carddata' => "BEGIN:VCARD\r\nEND:VCARD\r\n",
|
||||
'carddata' => "BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n",
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $this->cardBackend->getCard('addressbook1','blabla.vcf'));
|
||||
|
||||
}
|
||||
|
||||
function testCreateFileNoUID() {
|
||||
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf',
|
||||
));
|
||||
$request->setBody("BEGIN:VCARD\r\nEND:VCARD\r\n");
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 400 Bad request', $response->status, 'Incorrect status returned! Full response body: ' . $response->body);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function testCreateFileVCalendar() {
|
||||
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
|
@ -114,7 +129,7 @@ class Sabre_CardDAV_ValidateVCardTest extends PHPUnit_Framework_TestCase {
|
|||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf',
|
||||
));
|
||||
$body = "BEGIN:VCARD\r\nEND:VCARD\r\n";
|
||||
$body = "BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n";
|
||||
$request->setBody($body);
|
||||
|
||||
$response = $this->request($request);
|
||||
|
|
|
@ -6,6 +6,8 @@ class Sabre_DAV_ServerEventsTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
private $tempPath;
|
||||
|
||||
private $exception;
|
||||
|
||||
function testAfterBind() {
|
||||
|
||||
$this->server->subscribeEvent('afterBind',array($this,'afterBindHandler'));
|
||||
|
@ -47,5 +49,25 @@ class Sabre_DAV_ServerEventsTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
}
|
||||
|
||||
function testException() {
|
||||
|
||||
$this->server->subscribeEvent('exception', array($this, 'exceptionHandler'));
|
||||
|
||||
$req = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'REQUEST_URI' => '/not/exisitng',
|
||||
));
|
||||
$this->server->httpRequest = $req;
|
||||
$this->server->exec();
|
||||
|
||||
$this->assertInstanceOf('Sabre_DAV_Exception_NotFound', $this->exception);
|
||||
|
||||
}
|
||||
|
||||
function exceptionHandler(Exception $exception) {
|
||||
|
||||
$this->exception = $exception;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ class Sabre_DAV_Tree_FilesystemTest extends PHPUnit_Framework_TestCase {
|
|||
$fs = new Sabre_DAV_Tree_Filesystem(SABRE_TEMPDIR);
|
||||
$node = $fs->getNodeForPath('dir');
|
||||
$this->assertTrue($node instanceof Sabre_DAV_FS_Directory);
|
||||
$this->assertEquals('dir', $node->getName());
|
||||
$this->assertInternalType('array', $node->getChildren());
|
||||
|
||||
}
|
||||
|
||||
|
|
153
dav/SabreDAV/tests/Sabre/VObject/TimeZoneUtilTest.php
Normal file
153
dav/SabreDAV/tests/Sabre/VObject/TimeZoneUtilTest.php
Normal file
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
class Sabre_VObject_TimeZoneUtilTest extends PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @dataProvider getMapping
|
||||
*/
|
||||
function testCorrectTZ($timezoneName) {
|
||||
|
||||
$tz = new DateTimeZone($timezoneName);
|
||||
|
||||
}
|
||||
|
||||
function getMapping() {
|
||||
|
||||
// PHPUNit requires an array of arrays
|
||||
return array_map(
|
||||
function($value) {
|
||||
return array($value);
|
||||
},
|
||||
Sabre_VObject_TimeZoneUtil::$map
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testExchangeMap() {
|
||||
|
||||
$vobj = <<<HI
|
||||
BEGIN:VCALENDAR
|
||||
METHOD:REQUEST
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:foo
|
||||
X-MICROSOFT-CDO-TZID:2
|
||||
BEGIN:STANDARD
|
||||
DTSTART:16010101T030000
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
|
||||
END:STANDARD
|
||||
BEGIN:DAYLIGHT
|
||||
DTSTART:16010101T020000
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
|
||||
END:DAYLIGHT
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:20120416T092149Z
|
||||
DTSTART;TZID="foo":20120418T1
|
||||
00000
|
||||
SUMMARY:Begin Unterhaltsreinigung
|
||||
UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
|
||||
0100000008FECD2E607780649BE5A4C9EE6418CBC
|
||||
DTEND;TZID="Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb":20120418T103
|
||||
000
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
HI;
|
||||
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone('foo', Sabre_VObject_Reader::read($vobj));
|
||||
|
||||
$this->assertEquals(new DateTimeZone('Europe/Sarajevo'), $tz);
|
||||
|
||||
}
|
||||
|
||||
function testUnknownExchangeId() {
|
||||
|
||||
$vobj = <<<HI
|
||||
BEGIN:VCALENDAR
|
||||
METHOD:REQUEST
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:foo
|
||||
X-MICROSOFT-CDO-TZID:2000
|
||||
BEGIN:STANDARD
|
||||
DTSTART:16010101T030000
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
|
||||
END:STANDARD
|
||||
BEGIN:DAYLIGHT
|
||||
DTSTART:16010101T020000
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
|
||||
END:DAYLIGHT
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:20120416T092149Z
|
||||
DTSTART;TZID="foo":20120418T1
|
||||
00000
|
||||
SUMMARY:Begin Unterhaltsreinigung
|
||||
UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
|
||||
0100000008FECD2E607780649BE5A4C9EE6418CBC
|
||||
DTEND;TZID="Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb":20120418T103
|
||||
000
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
HI;
|
||||
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone('foo', Sabre_VObject_Reader::read($vobj));
|
||||
|
||||
$this->assertEquals(new DateTimeZone(date_default_timezone_get()), $tz);
|
||||
|
||||
}
|
||||
|
||||
function testWindowsTimeZone() {
|
||||
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone('Eastern Standard Time');
|
||||
$this->assertEquals(new DateTimeZone('America/New_York'), $tz);
|
||||
|
||||
}
|
||||
|
||||
function testFallBack() {
|
||||
|
||||
$vobj = <<<HI
|
||||
BEGIN:VCALENDAR
|
||||
METHOD:REQUEST
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:foo
|
||||
BEGIN:STANDARD
|
||||
DTSTART:16010101T030000
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
|
||||
END:STANDARD
|
||||
BEGIN:DAYLIGHT
|
||||
DTSTART:16010101T020000
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
|
||||
END:DAYLIGHT
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:20120416T092149Z
|
||||
DTSTART;TZID="foo":20120418T1
|
||||
00000
|
||||
SUMMARY:Begin Unterhaltsreinigung
|
||||
UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
|
||||
0100000008FECD2E607780649BE5A4C9EE6418CBC
|
||||
000
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
HI;
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone('foo', Sabre_VObject_Reader::read($vobj));
|
||||
|
||||
$this->assertEquals(new DateTimeZone(date_default_timezone_get()), $tz);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
$a = get_app();
|
||||
$uri = parse_url($a->get_baseurl());
|
||||
$path = "/";
|
||||
if (strlen($uri["path"]) > 1) {
|
||||
if (isset($uri["path"]) && strlen($uri["path"]) > 1) {
|
||||
$path = $uri["path"] . "/";
|
||||
}
|
||||
|
||||
|
@ -12,20 +12,24 @@ define("CALDAV_SQL_PREFIX", "dav_");
|
|||
define("CALDAV_URL_PREFIX", $path . "dav/");
|
||||
|
||||
define("CALDAV_NAMESPACE_PRIVATE", 1);
|
||||
define("CALDAV_NAMESPACE_FRIENDICA_NATIVE", 2);
|
||||
|
||||
define("CALDAV_FRIENDICA_MINE", 1);
|
||||
define("CALDAV_FRIENDICA_CONTACTS", 2);
|
||||
define("CALDAV_FRIENDICA_MINE", "friendica-mine");
|
||||
define("CALDAV_FRIENDICA_CONTACTS", "friendica-contacts");
|
||||
|
||||
$GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"] = array(CALDAV_FRIENDICA_MINE, CALDAV_FRIENDICA_CONTACTS);
|
||||
|
||||
define("CARDDAV_NAMESPACE_COMMUNITYCONTACTS", 1);
|
||||
define("CARDDAV_NAMESPACE_PHONECONTACTS", 2);
|
||||
|
||||
define("CALDAV_DB_VERSION", 1);
|
||||
define("CALDAV_DB_VERSION", 2);
|
||||
|
||||
define("CALDAV_MAX_YEAR", date("Y") + 5);
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
function getCurMicrotime () {
|
||||
function getCurMicrotime()
|
||||
{
|
||||
list($usec, $sec) = explode(" ", microtime());
|
||||
return sprintf("%14.0f", $sec * 10000 + $usec * 10000);
|
||||
} // function getCurMicrotime
|
||||
|
@ -33,7 +37,8 @@ function getCurMicrotime () {
|
|||
/**
|
||||
*
|
||||
*/
|
||||
function debug_time() {
|
||||
function debug_time()
|
||||
{
|
||||
$cur = getCurMicrotime();
|
||||
if ($GLOBALS["debug_time_last"] > 0) {
|
||||
echo "Zeit: " . ($cur - $GLOBALS["debug_time_last"]) . "<br>\n";
|
||||
|
@ -48,7 +53,7 @@ function debug_time() {
|
|||
*/
|
||||
function dav_compat_username2id($username = "")
|
||||
{
|
||||
$x = q("SELECT `uid` FROM user WHERE nickname='%s' AND account_removed = 0 AND account_expired = 0", dbesc($username));
|
||||
$x = q("SELECT `uid` FROM `user` WHERE `nickname`='%s' AND `account_removed` = 0 AND `account_expired` = 0", dbesc($username));
|
||||
if (count($x) == 1) return $x[0]["uid"];
|
||||
return null;
|
||||
}
|
||||
|
@ -59,7 +64,7 @@ function dav_compat_username2id($username = "")
|
|||
*/
|
||||
function dav_compat_id2username($id = 0)
|
||||
{
|
||||
$x = q("SELECT `nickname` FROM user WHERE uid = %i AND account_removed = 0 AND account_expired = 0", IntVal($id));
|
||||
$x = q("SELECT `nickname` FROM `user` WHERE `uid` = %i AND `account_removed` = 0 AND `account_expired` = 0", IntVal($id));
|
||||
if (count($x) == 1) return $x[0]["nickname"];
|
||||
return "";
|
||||
}
|
||||
|
@ -67,7 +72,8 @@ function dav_compat_id2username($id = 0)
|
|||
/**
|
||||
* @return int
|
||||
*/
|
||||
function dav_compat_get_curr_user_id() {
|
||||
function dav_compat_get_curr_user_id()
|
||||
{
|
||||
$a = get_app();
|
||||
return IntVal($a->user["uid"]);
|
||||
}
|
||||
|
@ -86,13 +92,34 @@ function dav_compat_principal2uid($principalUri = "")
|
|||
return dav_compat_username2id($username);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $principalUri
|
||||
* @return array|null
|
||||
*/
|
||||
function dav_compat_principal2namespace($principalUri = "")
|
||||
{
|
||||
if (strlen($principalUri) == 0) return null;
|
||||
if ($principalUri[0] == "/") $principalUri = substr($principalUri, 1);
|
||||
|
||||
if (strpos($principalUri, "principals/users/") !== 0) return null;
|
||||
$username = substr($principalUri, strlen("principals/users/"));
|
||||
return array("namespace" => CALDAV_NAMESPACE_PRIVATE, "namespace_id" => dav_compat_username2id($username));
|
||||
}
|
||||
|
||||
|
||||
function dav_compat_currentUserPrincipal() {
|
||||
$a = get_app();
|
||||
return "principals/users/" . strtolower($a->user["nickname"]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return null|string
|
||||
*/
|
||||
function dav_compat_getRequestVar($name = "") {
|
||||
if (x($_REQUEST, $name)) return $_REQUEST[$name];
|
||||
function dav_compat_getRequestVar($name = "")
|
||||
{
|
||||
if (isset($_REQUEST[$name])) return $_REQUEST[$name];
|
||||
else return null;
|
||||
}
|
||||
|
||||
|
@ -108,28 +135,49 @@ function dav_compat_parse_text_serverside($text)
|
|||
/**
|
||||
* @param string $uri
|
||||
*/
|
||||
function dav_compat_redirect($uri = "") {
|
||||
function dav_compat_redirect($uri = "")
|
||||
{
|
||||
goaway($uri);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return null|int
|
||||
*/
|
||||
function dav_compat_get_max_private_calendars()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user_id
|
||||
* @param int $namespace
|
||||
* @param int $namespace_id
|
||||
* @return AnimexxCalSource
|
||||
* @param string $uri
|
||||
* @param array $calendar
|
||||
* @return Sabre_CalDAV_Backend_Common
|
||||
* @throws Exception
|
||||
*/
|
||||
function wdcal_calendar_factory($user_id, $namespace, $namespace_id)
|
||||
function wdcal_calendar_factory($namespace, $namespace_id, $uri, $calendar = null)
|
||||
{
|
||||
switch ($namespace) {
|
||||
case CALDAV_NAMESPACE_PRIVATE:
|
||||
return new AnimexxCalSourcePrivate($user_id, $namespace_id);
|
||||
case CALDAV_NAMESPACE_FRIENDICA_NATIVE:
|
||||
return new FriendicaCalSourceEvents($user_id, $namespace_id);
|
||||
if ($uri == CALDAV_FRIENDICA_MINE || $uri == CALDAV_FRIENDICA_CONTACTS) return Sabre_CalDAV_Backend_Friendica::getInstance();
|
||||
else return Sabre_CalDAV_Backend_Private::getInstance();
|
||||
}
|
||||
throw new Exception("Calendar Namespace not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $calendar_id
|
||||
* @return Sabre_CalDAV_Backend_Common
|
||||
* @throws Exception
|
||||
*/
|
||||
function wdcal_calendar_factory_by_id($calendar_id) {
|
||||
$calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendar_id);
|
||||
return wdcal_calendar_factory($calendar["namespace"], $calendar["namespace_id"], $calendar["uri"], $calendar);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
@ -138,27 +186,19 @@ function wdcal_create_std_calendars()
|
|||
$a = get_app();
|
||||
if (!local_user()) return;
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `uid` = %d AND `namespace` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $a->user["uid"], CALDAV_NAMESPACE_PRIVATE);
|
||||
if (count($cals) == 0) {
|
||||
$maxid = q("SELECT MAX(`namespace_id`) maxid FROM %s%scalendars WHERE `namespace` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE);
|
||||
if (!$maxid) {
|
||||
notification("Something went wrong when trying to create your calendar.");
|
||||
goaway("/");
|
||||
killme();
|
||||
}
|
||||
$nextid = IntVal($maxid[0]["maxid"]) + 1;
|
||||
q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `uid`, `displayname`, `timezone`, `ctag`) VALUES (%d, %d, %d, '%s', '%s', 1)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, $nextid, $a->user["uid"], dbesc(t("Private Calendar")), dbesc($a->timezone)
|
||||
$uris = array(
|
||||
'private' => t("Private Calendar"),
|
||||
CALDAV_FRIENDICA_MINE => t("Friendica Events: Mine"),
|
||||
CALDAV_FRIENDICA_CONTACTS => t("Friendica Events: Contacts"),
|
||||
);
|
||||
}
|
||||
foreach ($uris as $uri => $name) {
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `uid` = %d AND `namespace` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $a->user["uid"], CALDAV_NAMESPACE_FRIENDICA_NATIVE);
|
||||
if (count($cals) < 2) {
|
||||
q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `uid`, `displayname`, `timezone`, `ctag`) VALUES (%d, %d, %d, '%s', '%s', 1)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_FRIENDICA_NATIVE, CALDAV_FRIENDICA_MINE, $a->user["uid"], dbesc(t("Friendica Events: Mine")), dbesc($a->timezone)
|
||||
);
|
||||
q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `uid`, `displayname`, `timezone`, `ctag`) VALUES (%d, %d, %d, '%s', '%s', 1)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_FRIENDICA_NATIVE, CALDAV_FRIENDICA_CONTACTS, $a->user["uid"], dbesc(t("Friendica Events: Contacts")), dbesc($a->timezone)
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, $a->user["uid"], dbesc($uri));
|
||||
if (count($cals) == 0) {
|
||||
q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `displayname`, `timezone`, `ctag`, `uri`, `has_vevent`, `has_vtodo`) VALUES (%d, %d, %d, '%s', '%s', 1, '%s', 1, 0)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"]), dbesc($name), dbesc($a->timezone), dbesc($uri)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<title>Really Simple Color Picker</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<script language="javascript" type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
|
||||
<script language="javascript" type="text/javascript" src="jquery.colorPicker.min.js"/></script>
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="jquery.colorPicker.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
//Run the code when document ready
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<?php
|
||||
|
||||
|
||||
define("DAV_ACL_READ", "{DAV:}read");
|
||||
define("DAV_ACL_WRITE", "{DAV:}write");
|
||||
define("DAV_DISPLAYNAME", "{DAV:}displayname");
|
||||
|
||||
|
||||
class vcard_source_data_email
|
||||
{
|
||||
public $email, $type;
|
||||
|
@ -83,7 +88,7 @@ class vcard_source_data
|
|||
/** @var array|vcard_source_data_email[] $email */
|
||||
public $emails;
|
||||
|
||||
/** @var array|vcard_source_data_addresses[] $addresses */
|
||||
/** @var array|vcard_source_data_address[] $addresses */
|
||||
public $addresses;
|
||||
|
||||
/** @var vcard_source_data_photo */
|
||||
|
@ -136,41 +141,6 @@ function vcard_source_compile($vcardsource)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $start
|
||||
* @param array $end
|
||||
* @param bool $allday
|
||||
* @return vevent
|
||||
*/
|
||||
function dav_create_vevent($start, $end, $allday)
|
||||
{
|
||||
if ($end["year"] < $start["year"] ||
|
||||
($end["year"] == $start["year"] && $end["month"] < $start["month"]) ||
|
||||
($end["year"] == $start["year"] && $end["month"] == $start["month"] && $end["day"] < $start["day"]) ||
|
||||
($end["year"] == $start["year"] && $end["month"] == $start["month"] && $end["day"] == $start["day"] && $end["hour"] < $start["hour"]) ||
|
||||
($end["year"] == $start["year"] && $end["month"] == $start["month"] && $end["day"] == $start["day"] && $end["hour"] == $start["hour"] && $end["minute"] < $start["minute"]) ||
|
||||
($end["year"] == $start["year"] && $end["month"] == $start["month"] && $end["day"] == $start["day"] && $end["hour"] == $start["hour"] && $end["minute"] == $start["minute"] && $end["second"] < $start["second"])
|
||||
) {
|
||||
$end = $start;
|
||||
} // DTEND muss <= DTSTART
|
||||
|
||||
$vevent = new vevent();
|
||||
if ($allday) {
|
||||
$vevent->setDtstart($start["year"], $start["month"], $start["day"], FALSE, FALSE, FALSE, FALSE, array("VALUE"=> "DATE"));
|
||||
$end = IntVal(mktime(0, 0, 0, $end["month"], $end["day"], $end["year"]) + 3600 * 24);
|
||||
|
||||
// If a DST change occurs on the current day
|
||||
$end += IntVal(date("Z", ($end - 3600 * 24)) - date("Z", $end));
|
||||
|
||||
$vevent->setDtend(date("Y", $end), date("m", $end), date("d", $end), FALSE, FALSE, FALSE, FALSE, array("VALUE"=> "DATE"));
|
||||
} else {
|
||||
$vevent->setDtstart($start["year"], $start["month"], $start["day"], $start["hour"], $start["minute"], $start["second"], FALSE, array("VALUE"=> "DATE-TIME"));
|
||||
$vevent->setDtend($end["year"], $end["month"], $end["day"], $end["hour"], $end["minute"], $end["second"], FALSE, array("VALUE"=> "DATE-TIME"));
|
||||
}
|
||||
return $vevent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $phpDate (UTC)
|
||||
* @return string (Lokalzeit)
|
||||
|
@ -216,457 +186,196 @@ function icalendar_sanitize_string($str = "")
|
|||
$str = str_replace("\r\n", "\n", $str);
|
||||
$str = str_replace("\n\r", "\n", $str);
|
||||
$str = str_replace("\r", "\n", $str);
|
||||
$str = str_replace("\n\n", "\n", $str);
|
||||
$str = str_replace("\n\n", "\n", $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param DBClass_friendica_calendars $calendar
|
||||
* @param DBClass_friendica_calendarobjects $calendarobject
|
||||
* @return Sabre_CalDAV_AnimexxCalendarRootNode
|
||||
*/
|
||||
function renderCalDavEntry_data(&$calendar, &$calendarobject)
|
||||
function dav_createRootCalendarNode()
|
||||
{
|
||||
$caldavBackend_std = Sabre_CalDAV_Backend_Private::getInstance();
|
||||
$caldavBackend_community = Sabre_CalDAV_Backend_Friendica::getInstance();
|
||||
|
||||
return new Sabre_CalDAV_AnimexxCalendarRootNode(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), array(
|
||||
$caldavBackend_std,
|
||||
$caldavBackend_community,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Sabre_CardDAV_AddressBookRootFriendica
|
||||
*/
|
||||
function dav_createRootContactsNode()
|
||||
{
|
||||
$carddavBackend_std = Sabre_CardDAV_Backend_Std::getInstance();
|
||||
$carddavBackend_community = Sabre_CardDAV_Backend_FriendicaCommunity::getInstance();
|
||||
|
||||
return new Sabre_CardDAV_AddressBookRootFriendica(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), array(
|
||||
$carddavBackend_std,
|
||||
$carddavBackend_community,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool $force_authentication
|
||||
* @param bool $needs_caldav
|
||||
* @param bool $needs_carddav
|
||||
* @return Sabre_DAV_Server
|
||||
*/
|
||||
function dav_create_server($force_authentication = false, $needs_caldav = true, $needs_carddav = true)
|
||||
{
|
||||
$arr = array(
|
||||
new Sabre_DAV_SimpleCollection('principals', array(
|
||||
new Sabre_CalDAV_Principal_Collection(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), "principals/users"),
|
||||
)),
|
||||
);
|
||||
if ($needs_caldav) $arr[] = dav_createRootCalendarNode();
|
||||
if ($needs_carddav) $arr[] = dav_createRootContactsNode();
|
||||
|
||||
|
||||
$tree = new Sabre_DAV_SimpleCollection('root', $arr);
|
||||
|
||||
// The object tree needs in turn to be passed to the server class
|
||||
$server = new Sabre_DAV_Server($tree);
|
||||
|
||||
$server->setBaseUri(CALDAV_URL_PREFIX);
|
||||
|
||||
$authPlugin = new Sabre_DAV_Auth_Plugin(Sabre_DAV_Auth_Backend_Std::getInstance(), 'SabreDAV');
|
||||
$server->addPlugin($authPlugin);
|
||||
|
||||
$aclPlugin = new Sabre_DAVACL_Plugin_Friendica();
|
||||
$aclPlugin->defaultUsernamePath = "principals/users";
|
||||
$server->addPlugin($aclPlugin);
|
||||
|
||||
if ($needs_caldav) {
|
||||
$caldavPlugin = new Sabre_CalDAV_Plugin();
|
||||
$server->addPlugin($caldavPlugin);
|
||||
}
|
||||
if ($needs_carddav) {
|
||||
$carddavPlugin = new Sabre_CardDAV_Plugin();
|
||||
$server->addPlugin($carddavPlugin);
|
||||
}
|
||||
|
||||
if ($force_authentication) $server->broadcastEvent('beforeMethod', array("GET", "/")); // Make it authenticate
|
||||
|
||||
return $server;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param string $with_privilege
|
||||
* @return array|Sabre_CalDAV_Calendar[]
|
||||
*/
|
||||
function dav_get_current_user_calendars(&$server, $with_privilege = "")
|
||||
{
|
||||
if ($with_privilege == "") $with_privilege = DAV_ACL_READ;
|
||||
|
||||
$a = get_app();
|
||||
$calendar_path = "/calendars/" . strtolower($a->user["nickname"]) . "/";
|
||||
|
||||
/** @var Sabre_CalDAV_AnimexxUserCalendars $tree */
|
||||
$tree = $server->tree->getNodeForPath($calendar_path);
|
||||
/** @var array|Sabre_CalDAV_Calendar[] $calendars */
|
||||
$children = $tree->getChildren();
|
||||
|
||||
$calendars = array();
|
||||
/** @var Sabre_DAVACL_Plugin $aclplugin */
|
||||
$aclplugin = $server->getPlugin("acl");
|
||||
foreach ($children as $child) if (is_a($child, "Sabre_CalDAV_Calendar")) {
|
||||
if ($with_privilege != "") {
|
||||
$caluri = $calendar_path . $child->getName();
|
||||
if ($aclplugin->checkPrivileges($caluri, $with_privilege, Sabre_DAVACL_Plugin::R_PARENT, false)) $calendars[] = $child;
|
||||
} else {
|
||||
$calendars[] = $child;
|
||||
}
|
||||
}
|
||||
return $calendars;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param Sabre_CalDAV_Calendar $calendar
|
||||
* @param string $calendarobject_uri
|
||||
* @param string $with_privilege
|
||||
* @return null|Sabre_VObject_Component_VEvent
|
||||
*/
|
||||
function dav_get_current_user_calendarobject(&$server, &$calendar, $calendarobject_uri, $with_privilege = "")
|
||||
{
|
||||
$obj = $calendar->getChild($calendarobject_uri);
|
||||
|
||||
if ($with_privilege == "") $with_privilege = DAV_ACL_READ;
|
||||
|
||||
$a = get_app();
|
||||
$uri = "/calendars/" . strtolower($a->user["nickname"]) . "/" . $calendar->getName() . "/" . $calendarobject_uri;
|
||||
|
||||
/** @var Sabre_DAVACL_Plugin $aclplugin */
|
||||
$aclplugin = $server->getPlugin("acl");
|
||||
if (!$aclplugin->checkPrivileges($uri, $with_privilege, Sabre_DAVACL_Plugin::R_PARENT, false)) return null;
|
||||
|
||||
$data = $obj->get();
|
||||
$vObject = Sabre_VObject_Reader::read($data);
|
||||
|
||||
return $vObject;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param int $id
|
||||
* @param string $with_privilege
|
||||
* @return null|Sabre_CalDAV_Calendar
|
||||
*/
|
||||
function dav_get_current_user_calendar_by_id(&$server, $id, $with_privilege = "")
|
||||
{
|
||||
$calendars = dav_get_current_user_calendars($server, $with_privilege);
|
||||
|
||||
$calendar = null;
|
||||
foreach ($calendars as $cal) {
|
||||
$prop = $cal->getProperties(array("id"));
|
||||
if (isset($prop["id"]) && $prop["id"] == $id) $calendar = $cal;
|
||||
}
|
||||
|
||||
return $calendar;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uid
|
||||
* @return Sabre_VObject_Component_VEvent $vObject
|
||||
*/
|
||||
function dav_create_empty_vevent($uid = "")
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
$v = new vcalendar();
|
||||
$v->setConfig('unique_id', $a->get_hostname());
|
||||
$v->parse($calendarobject->calendardata);
|
||||
$v->sort();
|
||||
|
||||
$eventArray = $v->selectComponents(2009, 1, 1, date("Y") + 2, 12, 30);
|
||||
|
||||
$start_min = $end_max = "";
|
||||
|
||||
$allday = $summary = $vevent = $rrule = $color = $start = $end = null;
|
||||
$location = $description = "";
|
||||
|
||||
foreach ($eventArray as $yearArray) {
|
||||
foreach ($yearArray as $monthArray) {
|
||||
foreach ($monthArray as $day => $dailyEventsArray) {
|
||||
foreach ($dailyEventsArray as $vevent) {
|
||||
/** @var $vevent vevent */
|
||||
$start = "";
|
||||
$rrule = "NULL";
|
||||
$allday = 0;
|
||||
|
||||
$dtstart = $vevent->getProperty('X-CURRENT-DTSTART');
|
||||
if (is_array($dtstart)) {
|
||||
$start = "'" . $dtstart[1] . "'";
|
||||
if (strpos($dtstart[1], ":") === false) $allday = 1;
|
||||
} else {
|
||||
$dtstart = $vevent->getProperty('dtstart');
|
||||
if (isset($dtstart["day"]) && $dtstart["day"] == $day) { // Mehrtägige Events nur einmal rein
|
||||
if (isset($dtstart["hour"])) $start = "'" . $dtstart["year"] . "-" . $dtstart["month"] . "-" . $dtstart["day"] . " " . $dtstart["hour"] . ":" . $dtstart["minute"] . ":" . $dtstart["secont"] . "'";
|
||||
else {
|
||||
$start = "'" . $dtstart["year"] . "-" . $dtstart["month"] . "-" . $dtstart["day"] . " 00:00:00'";
|
||||
$allday = 1;
|
||||
if ($uid == "") $uid = uniqid();
|
||||
return Sabre_VObject_Reader::read("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Friendica//DAV-Plugin//EN\r\nBEGIN:VEVENT\r\nUID:" . $uid . "@" . $a->get_hostname() .
|
||||
"\r\nDTSTAMP:" . date("Ymd") . "T" . date("His") . "Z\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dtend = $vevent->getProperty('X-CURRENT-DTEND');
|
||||
if (is_array($dtend)) {
|
||||
$end = "'" . $dtend[1] . "'";
|
||||
if (strpos($dtend[1], ":") === false) $allday = 1;
|
||||
} else {
|
||||
$dtend = $vevent->getProperty('dtend');
|
||||
if (isset($dtend["hour"])) $end = "'" . $dtend["year"] . "-" . $dtend["month"] . "-" . $dtend["day"] . " " . $dtend["hour"] . ":" . $dtend["minute"] . ":" . $dtend["second"] . "'";
|
||||
else {
|
||||
$end = "'" . $dtend["year"] . "-" . $dtend["month"] . "-" . $dtend["day"] . " 00:00:00' - INTERVAL 1 SECOND";
|
||||
$allday = 1;
|
||||
}
|
||||
}
|
||||
$summary = $vevent->getProperty('summary');
|
||||
$description = $vevent->getProperty('description');
|
||||
$location = $vevent->getProperty('location');
|
||||
$rrule_prob = $vevent->getProperty('rrule');
|
||||
if ($rrule_prob != null) {
|
||||
$rrule = $vevent->createRrule();
|
||||
$rrule = "'" . dbesc($rrule) . "'";
|
||||
}
|
||||
$color_ = $vevent->getProperty("X-ANIMEXX-COLOR");
|
||||
$color = (is_array($color_) ? $color_[1] : "NULL");
|
||||
|
||||
if ($start_min == "" || preg_replace("/[^0-9]/", "", $start) < preg_replace("/[^0-9]/", "", $start_min)) $start_min = $start;
|
||||
if ($end_max == "" || preg_replace("/[^0-9]/", "", $end) > preg_replace("/[^0-9]/", "", $start_min)) $end_max = $end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($start_min != "") {
|
||||
|
||||
if ($allday && mb_strlen($end_max) == 12) {
|
||||
$x = explode("-", str_replace("'", "", $end_max));
|
||||
$time = mktime(0, 0, 0, IntVal($x[1]), IntVal($x[2]), IntVal($x[0]));
|
||||
$end_max = date("'Y-m-d H:i:s'", ($time - 1));
|
||||
}
|
||||
|
||||
q("INSERT INTO %s%sjqcalendar (`uid`, `namespace`, `namespace_id`, `ical_uri`, `Subject`, `Location`, `Description`, `StartTime`, `EndTime`, `IsAllDayEvent`, `RecurringRule`, `Color`)
|
||||
VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', %s, %s, %d, '%s', '%s')",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
|
||||
IntVal($calendar->uid), IntVal($calendarobject->namespace), IntVal($calendarobject->namespace_id), dbesc($calendarobject->uri), dbesc($summary),
|
||||
dbesc($location), dbesc(str_replace("\\n", "\n", $description)), $start_min, $end_max, IntVal($allday), dbesc($rrule), dbesc($color)
|
||||
);
|
||||
|
||||
foreach ($vevent->components as $comp) {
|
||||
/** @var $comp calendarComponent */
|
||||
$trigger = $comp->getProperty("TRIGGER");
|
||||
$sql_field = ($trigger["relatedStart"] ? $start : $end);
|
||||
$sql_op = ($trigger["before"] ? "DATE_SUB" : "DATE_ADD");
|
||||
$num = "";
|
||||
$rel_type = "";
|
||||
$rel_value = 0;
|
||||
if (isset($trigger["second"])) {
|
||||
$num = IntVal($trigger["second"]) . " SECOND";
|
||||
$rel_type = "second";
|
||||
$rel_value = IntVal($trigger["second"]);
|
||||
}
|
||||
if (isset($trigger["minute"])) {
|
||||
$num = IntVal($trigger["minute"]) . " MINUTE";
|
||||
$rel_type = "minute";
|
||||
$rel_value = IntVal($trigger["minute"]);
|
||||
}
|
||||
if (isset($trigger["hour"])) {
|
||||
$num = IntVal($trigger["hour"]) . " HOUR";
|
||||
$rel_type = "hour";
|
||||
$rel_value = IntVal($trigger["hour"]);
|
||||
}
|
||||
if (isset($trigger["day"])) {
|
||||
$num = IntVal($trigger["day"]) . " DAY";
|
||||
$rel_type = "day";
|
||||
$rel_value = IntVal($trigger["day"]);
|
||||
}
|
||||
if (isset($trigger["week"])) {
|
||||
$num = IntVal($trigger["week"]) . " WEEK";
|
||||
$rel_type = "week";
|
||||
$rel_value = IntVal($trigger["week"]);
|
||||
}
|
||||
if (isset($trigger["month"])) {
|
||||
$num = IntVal($trigger["month"]) . " MONTH";
|
||||
$rel_type = "month";
|
||||
$rel_value = IntVal($trigger["month"]);
|
||||
}
|
||||
if (isset($trigger["year"])) {
|
||||
$num = IntVal($trigger["year"]) . " YEAR";
|
||||
$rel_type = "year";
|
||||
$rel_value = IntVal($trigger["year"]);
|
||||
}
|
||||
if ($trigger["before"]) $rel_value *= -1;
|
||||
|
||||
if ($rel_type != "") {
|
||||
$not_date = "$sql_op($sql_field, INTERVAL $num)";
|
||||
q("INSERT INTO %s%snotifications (`uid`, `ical_uri`, `rel_type`, `rel_value`, `alert_date`, `notified`) VALUES ('%s', '%s', '%s', '%s', %s, IF(%s < NOW(), 1, 0))",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
|
||||
IntVal($calendar->uid), dbesc($calendarobject->uri), dbesc($rel_type), IntVal($rel_value), $not_date, $not_date);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function renderAllCalDavEntries()
|
||||
{
|
||||
q("DELETE FROM %s%sjqcalendar", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
q("DELETE FROM %s%snotifications", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
$calendars = q("SELECT * FROM %s%scalendars", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
$anz = count($calendars);
|
||||
$i = 0;
|
||||
foreach ($calendars as $calendar) {
|
||||
$cal = new DBClass_friendica_calendars($calendar);
|
||||
$i++;
|
||||
if (($i % 100) == 0) echo "$i / $anz\n";
|
||||
$calobjs = q("SELECT * FROM %s%scalendarobjects WHERE `namespace` = %d AND `namespace_id` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendar["namespace"]), IntVal($calendar["namespace_id"]));
|
||||
foreach ($calobjs as $calobj) {
|
||||
$obj = new DBClass_friendica_calendarobjects($calobj);
|
||||
renderCalDavEntry_data($cal, $obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @return bool
|
||||
*/
|
||||
function renderCalDavEntry_uri($uri)
|
||||
{
|
||||
q("DELETE FROM %s%sjqcalendar WHERE `ical_uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($uri));
|
||||
q("DELETE FROM %s%snotifications WHERE `ical_uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($uri));
|
||||
|
||||
$calobj = q("SELECT * FROM %s%scalendarobjects WHERE `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($uri));
|
||||
if (count($calobj) == 0) return false;
|
||||
$cal = new DBClass_friendica_calendarobjects($calobj[0]);
|
||||
$calendars = q("SELECT * FROM %s%scalendars WHERE `namespace`=%d AND `namespace_id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($cal->namespace), IntVal($cal->namespace_id));
|
||||
$calendar = new DBClass_friendica_calendars($calendars[0]);
|
||||
renderCalDavEntry_data($calendar, $cal);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $user_id
|
||||
* @return array|DBClass_friendica_calendars[]
|
||||
*/
|
||||
function dav_getMyCals($user_id)
|
||||
{
|
||||
$d = q("SELECT * FROM %s%scalendars WHERE `uid` = %d ORDER BY `calendarorder` ASC",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($user_id), CALDAV_NAMESPACE_PRIVATE
|
||||
);
|
||||
$cals = array();
|
||||
foreach ($d as $e) $cals[] = new DBClass_friendica_calendars($e);
|
||||
return $cals;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $obj
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_jsonp_encode($obj)
|
||||
{
|
||||
$str = json_encode($obj);
|
||||
if (isset($_REQUEST["callback"])) {
|
||||
$str = $_REQUEST["callback"] . "(" . $str . ")";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $day
|
||||
* @param int $weekstartday
|
||||
* @param int $num_days
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
function wdcal_get_list_range_params($day, $weekstartday, $num_days, $type)
|
||||
{
|
||||
$phpTime = IntVal($day);
|
||||
switch ($type) {
|
||||
case "month":
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), 1, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime) + 1, 1, date("Y", $phpTime));
|
||||
break;
|
||||
case "week":
|
||||
//suppose first day of a week is monday
|
||||
$monday = date("d", $phpTime) - date('N', $phpTime) + 1;
|
||||
//echo date('N', $phpTime);
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), $monday, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), $monday + 7, date("Y", $phpTime));
|
||||
break;
|
||||
case "multi_days":
|
||||
//suppose first day of a week is monday
|
||||
$monday = date("d", $phpTime) - date('N', $phpTime) + $weekstartday;
|
||||
//echo date('N', $phpTime);
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), $monday, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), $monday + $num_days, date("Y", $phpTime));
|
||||
break;
|
||||
case "day":
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), date("d", $phpTime), date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), date("d", $phpTime) + 1, date("Y", $phpTime));
|
||||
break;
|
||||
default:
|
||||
return array(0, 0);
|
||||
}
|
||||
return array($st, $et);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param string $recurr_uri
|
||||
* @param int $uid
|
||||
* @param string $timezone
|
||||
* @param string $goaway_url
|
||||
* @return string
|
||||
* @param Sabre_VObject_Component_VEvent $vObject
|
||||
* @return Sabre_VObject_Component_VEvent|null
|
||||
*/
|
||||
function wdcal_postEditPage($uri, $recurr_uri = "", $uid = 0, $timezone = "", $goaway_url = "")
|
||||
function dav_get_eventComponent(&$vObject)
|
||||
{
|
||||
$uid = IntVal($uid);
|
||||
$localization = wdcal_local::getInstanceByUser($uid);
|
||||
|
||||
if (isset($_REQUEST["allday"])) {
|
||||
$start = $localization->date_parseLocal($_REQUEST["start_date"] . " 00:00");
|
||||
$end = $localization->date_parseLocal($_REQUEST["end_date"] . " 20:00");
|
||||
$isallday = true;
|
||||
} else {
|
||||
$start = $localization->date_parseLocal($_REQUEST["start_date"] . " " . $_REQUEST["start_time"]);
|
||||
$end = $localization->date_parseLocal($_REQUEST["end_date"] . " " . $_REQUEST["end_time"]);
|
||||
$isallday = false;
|
||||
}
|
||||
|
||||
if ($uri == "new") {
|
||||
$cals = dav_getMyCals($uid);
|
||||
foreach ($cals as $c) {
|
||||
$cs = wdcal_calendar_factory($uid, $c->namespace, $c->namespace_id);
|
||||
$p = $cs->getPermissionsCalendar($uid);
|
||||
|
||||
if ($p["write"]) try {
|
||||
$cs->addItem($start, $end, dav_compat_getRequestVar("subject"), $isallday, dav_compat_parse_text_serverside("wdcal_desc"),
|
||||
dav_compat_getRequestVar("location"), dav_compat_getRequestVar("color"), $timezone,
|
||||
isset($_REQUEST["notification"]), $_REQUEST["notification_type"], $_REQUEST["notification_value"]);
|
||||
} catch (Exception $e) {
|
||||
notification(t("Error") . ": " . $e);
|
||||
}
|
||||
dav_compat_redirect($goaway_url);
|
||||
}
|
||||
|
||||
} else {
|
||||
$cals = dav_getMyCals($uid);
|
||||
foreach ($cals as $c) {
|
||||
$cs = wdcal_calendar_factory($uid, $c->namespace, $c->namespace_id);
|
||||
$p = $cs->getPermissionsItem($uid, $uri, $recurr_uri);
|
||||
if ($p["write"]) try {
|
||||
$cs->updateItem($uri, $start, $end,
|
||||
dav_compat_getRequestVar("subject"), $isallday, dav_compat_parse_text_serverside("wdcal_desc"),
|
||||
dav_compat_getRequestVar("location"), dav_compat_getRequestVar("color"), $timezone,
|
||||
isset($_REQUEST["notification"]), $_REQUEST["notification_type"], $_REQUEST["notification_value"]);
|
||||
} catch (Exception $e) {
|
||||
notification(t("Error") . ": " . $e);
|
||||
}
|
||||
dav_compat_redirect($goaway_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function wdcal_print_feed($base_path = "")
|
||||
{
|
||||
$user_id = dav_compat_get_curr_user_id();
|
||||
$cals = array();
|
||||
if (isset($_REQUEST["cal"])) foreach ($_REQUEST["cal"] as $c) {
|
||||
$x = explode("-", $c);
|
||||
$calendarSource = wdcal_calendar_factory($user_id, $x[0], $x[1]);
|
||||
$calp = $calendarSource->getPermissionsCalendar($user_id);
|
||||
if ($calp["read"]) $cals[] = $calendarSource;
|
||||
}
|
||||
|
||||
$ret = null;
|
||||
/** @var $cals array|AnimexxCalSource[] */
|
||||
|
||||
$method = $_GET["method"];
|
||||
switch ($method) {
|
||||
case "add":
|
||||
$cs = null;
|
||||
foreach ($cals as $c) if ($cs == null) {
|
||||
$x = $c->getPermissionsCalendar($user_id);
|
||||
if ($x["read"]) $cs = $c;
|
||||
}
|
||||
if ($cs == null) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
try {
|
||||
$start = wdcal_mySql2icalTime(wdcal_php2MySqlTime($_REQUEST["CalendarStartTime"]));
|
||||
$end = wdcal_mySql2icalTime(wdcal_php2MySqlTime($_REQUEST["CalendarEndTime"]));
|
||||
$newuri = $cs->addItem($start, $end, $_REQUEST["CalendarTitle"], $_REQUEST["IsAllDayEvent"]);
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'add success',
|
||||
'Data' => $newuri,
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$ret = array(
|
||||
'IsSuccess' => false,
|
||||
'Msg' => $e->__toString(),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "list":
|
||||
$weekstartday = (isset($_REQUEST["weekstartday"]) ? IntVal($_REQUEST["weekstartday"]) : 1); // 1 = Monday
|
||||
$num_days = (isset($_REQUEST["num_days"]) ? IntVal($_REQUEST["num_days"]) : 7);
|
||||
$ret = null;
|
||||
|
||||
$date = wdcal_get_list_range_params($_REQUEST["showdate"], $weekstartday, $num_days, $_REQUEST["viewtype"]);
|
||||
$ret = array();
|
||||
$ret['events'] = array();
|
||||
$ret["issort"] = true;
|
||||
$ret["start"] = $date[0];
|
||||
$ret["end"] = $date[1];
|
||||
$ret['error'] = null;
|
||||
|
||||
foreach ($cals as $c) {
|
||||
$events = $c->listItemsByRange($date[0], $date[1], $base_path);
|
||||
$ret["events"] = array_merge($ret["events"], $events);
|
||||
}
|
||||
|
||||
$tmpev = array();
|
||||
foreach ($ret["events"] as $e) {
|
||||
if (!isset($tmpev[$e["start"]])) $tmpev[$e["start"]] = array();
|
||||
$tmpev[$e["start"]][] = $e;
|
||||
}
|
||||
ksort($tmpev);
|
||||
$ret["events"] = array();
|
||||
foreach ($tmpev as $e) foreach ($e as $f) $ret["events"][] = $f;
|
||||
|
||||
break;
|
||||
case "update":
|
||||
$found = false;
|
||||
$start = wdcal_mySql2icalTime(wdcal_php2MySqlTime($_REQUEST["CalendarStartTime"]));
|
||||
$end = wdcal_mySql2icalTime(wdcal_php2MySqlTime($_REQUEST["CalendarEndTime"]));
|
||||
foreach ($cals as $c) try {
|
||||
$permissions_item = $c->getPermissionsItem($user_id, $_REQUEST["calendarId"], "");
|
||||
if ($permissions_item["write"]) {
|
||||
$c->updateItem($_REQUEST["calendarId"], $start, $end);
|
||||
$found = true;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
;
|
||||
|
||||
if ($found) {
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'Succefully',
|
||||
);
|
||||
} else {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
|
||||
try {
|
||||
} catch (Exception $e) {
|
||||
$ret = array(
|
||||
'IsSuccess' => false,
|
||||
'Msg' => $e->__toString(),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "remove":
|
||||
$found = false;
|
||||
foreach ($cals as $c) try {
|
||||
$permissions_item = $c->getPermissionsItem($user_id, $_REQUEST["calendarId"], "");
|
||||
if ($permissions_item["write"]) $c->removeItem($_REQUEST["calendarId"]);
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'Succefully',
|
||||
);
|
||||
} else {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
$component = null;
|
||||
$componentType = "";
|
||||
foreach ($vObject->getComponents() as $component) {
|
||||
if ($component->name !== 'VTIMEZONE') {
|
||||
$componentType = $component->name;
|
||||
break;
|
||||
}
|
||||
echo wdcal_jsonp_encode($ret);
|
||||
killme();
|
||||
}
|
||||
if ($componentType != "VEVENT") return null;
|
||||
|
||||
return $component;
|
||||
}
|
||||
|
|
185
dav/common/calendar_rendering.fnk.php
Normal file
185
dav/common/calendar_rendering.fnk.php
Normal file
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_VObject_Component_VAlarm $alarm
|
||||
* @param Sabre_VObject_Component_VEvent|Sabre_VObject_Component_VTodo $parent
|
||||
* @return DateTime|null
|
||||
* @throws Sabre_DAV_Exception
|
||||
*/
|
||||
function renderCalDavEntry_calcalarm(&$alarm, &$parent)
|
||||
{
|
||||
$trigger = $alarm->__get("TRIGGER");
|
||||
if (!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') {
|
||||
$triggerDuration = Sabre_VObject_DateTimeParser::parseDuration($trigger);
|
||||
|
||||
$related = (isset($trigger['RELATED']) && strtoupper($trigger['RELATED']) == 'END') ? 'END' : 'START';
|
||||
|
||||
if ($related === 'START') {
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $parent->__get("DTSTART");
|
||||
$effectiveTrigger = $dtstart->getDateTime();
|
||||
$effectiveTrigger->add($triggerDuration);
|
||||
} else {
|
||||
if ($parent->name === 'VTODO') {
|
||||
$endProp = 'DUE';
|
||||
} else {
|
||||
$endProp = 'DTEND';
|
||||
}
|
||||
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $parent->__get("DTSTART");
|
||||
if (isset($parent->$endProp)) {
|
||||
$effectiveTrigger = clone $parent->$endProp->getDateTime();
|
||||
$effectiveTrigger->add($triggerDuration);
|
||||
} elseif ($parent->__get("DURATION") != "") {
|
||||
$effectiveTrigger = clone $dtstart->getDateTime();
|
||||
$duration = Sabre_VObject_DateTimeParser::parseDuration($parent->__get("DURATION"));
|
||||
$effectiveTrigger->add($duration);
|
||||
$effectiveTrigger->add($triggerDuration);
|
||||
} else {
|
||||
$effectiveTrigger = clone $dtstart->getDateTime();
|
||||
$effectiveTrigger->add($triggerDuration);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ??? @TODO
|
||||
$effectiveTrigger = $trigger->getDateTime();
|
||||
}
|
||||
return $effectiveTrigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $calendar
|
||||
* @param array $calendarobject
|
||||
* @throws Sabre_DAV_Exception_BadRequest
|
||||
* @return void
|
||||
*/
|
||||
function renderCalDavEntry_data(&$calendar, &$calendarobject)
|
||||
{
|
||||
/** @var Sabre_VObject_Component_VCalendar $vObject */
|
||||
$vObject = Sabre_VObject_Reader::read($calendarobject["calendardata"]);
|
||||
$componentType = null;
|
||||
/** @var Sabre_VObject_Component_VEvent $component */
|
||||
$component = null;
|
||||
foreach ($vObject->getComponents() as $component) {
|
||||
if ($component->name !== 'VTIMEZONE') {
|
||||
$componentType = $component->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$componentType) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
|
||||
}
|
||||
|
||||
|
||||
if ($componentType !== 'VEVENT') return;
|
||||
|
||||
$event = array(
|
||||
"description" => ($component->__get("DESCRIPTION") ? $component->__get("DESCRIPTION")->value : null),
|
||||
"summary" => ($component->__get("SUMMARY") ? $component->__get("SUMMARY")->value : null),
|
||||
"location" => ($component->__get("LOCATION") ? $component->__get("LOCATION")->value : null),
|
||||
"color" => ($component->__get("X-ANIMEXX-COLOR") ? $component->__get("X-ANIMEXX-COLOR")->value : null),
|
||||
);
|
||||
|
||||
$recurring = ($component->__get("RRULE") ? 1 : 0);
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $component->__get("DTSTART");
|
||||
$allday = ($dtstart->getDateType() == Sabre_VObject_Property_DateTime::DATE ? 1 : 0);
|
||||
|
||||
/** @var array|Sabre_VObject_Component_VAlarm[] $alarms */
|
||||
$alarms = array();
|
||||
foreach ($component->getComponents() as $a_component) if ($a_component->name == "VALARM") {
|
||||
/** var Sabre_VObject_Component_VAlarm $component */
|
||||
$alarms[] = $a_component;
|
||||
}
|
||||
|
||||
$it = new Sabre_VObject_RecurrenceIterator($vObject, (string)$component->__get("UID"));
|
||||
$last_end = 0;
|
||||
$max_ts = mktime(0, 0, 0, 1, 1, CALDAV_MAX_YEAR * 1);
|
||||
$first = true;
|
||||
|
||||
while ($it->valid() && $last_end < $max_ts && ($recurring || $first)) {
|
||||
$first = false;
|
||||
$last_end = $it->getDtEnd()->getTimestamp();
|
||||
$start = $it->getDtStart()->getTimestamp();
|
||||
|
||||
q("INSERT INTO %s%sjqcalendar (`calendar_id`, `calendarobject_id`, `Summary`, `StartTime`, `EndTime`, `IsEditable`, `IsAllDayEvent`, `IsRecurring`, `Color`) VALUES
|
||||
(%d, %d, '%s', '%s', '%s', %d, %d, %d, '%s')", CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
|
||||
IntVal($calendar["id"]), IntVal($calendarobject["id"]), dbesc($event["summary"]), date("Y-m-d H:i:s", $start), date("Y-m-d H:i:s", $last_end),
|
||||
1, $allday, $recurring, dbesc(substr($event["color"], 1))
|
||||
);
|
||||
|
||||
foreach ($alarms as $alarm) {
|
||||
$alarm = renderCalDavEntry_calcalarm($alarm, $component);
|
||||
$notified = ($alarm->getTimestamp() < time() ? 1 : 0);
|
||||
q("INSERT INTO %s%snotifications (`calendar_id`, `calendarobject_id`, `alert_date`, `notified`) VALUES (%d, %d, '%s', %d)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendar["id"]), IntVal($calendarobject["id"]), $alarm->format("Y-m-d H:i:s"), $notified
|
||||
);
|
||||
}
|
||||
|
||||
$it->next();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function renderAllCalDavEntries()
|
||||
{
|
||||
q("DELETE FROM %s%sjqcalendar", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
q("DELETE FROM %s%snotifications", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
$calendars = q("SELECT * FROM %s%scalendars", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
$anz = count($calendars);
|
||||
$i = 0;
|
||||
foreach ($calendars as $calendar) {
|
||||
$i++;
|
||||
if (($i % 100) == 0) echo "$i / $anz\n";
|
||||
$calobjs = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendar["id"]));
|
||||
foreach ($calobjs as $calobj) renderCalDavEntry_data($calendar, $calobj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @return bool
|
||||
*/
|
||||
function renderCalDavEntry_uri($uri)
|
||||
{
|
||||
$calobj = q("SELECT * FROM %s%scalendarobjects WHERE `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($uri));
|
||||
if (count($calobj) == 0) return false;
|
||||
|
||||
q("DELETE FROM %s%sjqcalendar WHERE `calendar_id` = %d AND `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calobj[0]["calendar_id"]), IntVal($calobj[0]["id"]));
|
||||
q("DELETE FROM %s%snotifications WHERE `calendar_id` = %d AND `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calobj[0]["calendar_id"]), IntVal($calobj[0]["id"]));
|
||||
|
||||
$calendars = q("SELECT * FROM %s%scalendars WHERE `id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calobj[0]["calendar_id"]));
|
||||
|
||||
renderCalDavEntry_data($calendars[0], $calobj[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $calobj_id
|
||||
* @return bool
|
||||
*/
|
||||
function renderCalDavEntry_calobj_id($calobj_id)
|
||||
{
|
||||
$calobj_id = IntVal($calobj_id);
|
||||
q("DELETE FROM %s%sjqcalendar WHERE `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calobj_id);
|
||||
q("DELETE FROM %s%snotifications WHERE `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calobj_id);
|
||||
|
||||
$calobj = q("SELECT * FROM %s%scalendarobjects WHERE `id` = '%d'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calobj_id);
|
||||
if (count($calobj) == 0) return false;
|
||||
|
||||
$calendars = q("SELECT * FROM %s%scalendars WHERE `id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calobj[0]["calendar_id"]));
|
||||
|
||||
renderCalDavEntry_data($calendars[0], $calobj[0]);
|
||||
return true;
|
||||
}
|
|
@ -1,14 +1,11 @@
|
|||
<?php
|
||||
|
||||
abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract {
|
||||
abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract
|
||||
{
|
||||
/**
|
||||
* List of CalDAV properties, and how they map to database fieldnames
|
||||
*
|
||||
* Add your own properties by simply adding on to this array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $propertyMap = array(
|
||||
protected $propertyMap = array(
|
||||
'{DAV:}displayname' => 'displayname',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'timezone',
|
||||
|
@ -17,60 +14,158 @@ abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract
|
|||
);
|
||||
|
||||
|
||||
abstract public function getNamespace();
|
||||
abstract public function getCalUrlPrefix();
|
||||
|
||||
/**
|
||||
* @param int $namespace
|
||||
* @param int $namespace_id
|
||||
* @abstract
|
||||
* @return int
|
||||
*/
|
||||
protected function increaseCalendarCtag($namespace, $namespace_id) {
|
||||
$namespace = IntVal($namespace);
|
||||
$namespace_id = IntVal($namespace_id);
|
||||
|
||||
q("UPDATE %s%scalendars SET `ctag` = `ctag` + 1 WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $namespace, $namespace_id);
|
||||
}
|
||||
|
||||
abstract public function getNamespace();
|
||||
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param int $calendarId
|
||||
* @param string $sd
|
||||
* @param string $ed
|
||||
* @param string $base_path
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri)
|
||||
abstract public function listItemsByRange($calendarId, $sd, $ed, $base_path);
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static private $calendarCache = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static private $calendarObjectCache = array();
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $calendarId
|
||||
* @return array
|
||||
*/
|
||||
static public function loadCalendarById($calendarId)
|
||||
{
|
||||
list(,$name) = Sabre_DAV_URLUtil::splitPath($principalUri);
|
||||
$user_id = dav_compat_username2id($name);
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `uid`=%d AND `namespace` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $user_id, $this->getNamespace());
|
||||
$ret = array();
|
||||
foreach ($cals as $cal) {
|
||||
$dat = array(
|
||||
"id" => $cal["namespace"] . "-" . $cal["namespace_id"],
|
||||
"uri" => $this->getCalUrlPrefix() . "-" . $cal["namespace_id"],
|
||||
"principaluri" => $principalUri,
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}getctag' => $cal['ctag']?$cal['ctag']:'0',
|
||||
"calendar_class" => "Sabre_CalDAV_Calendar",
|
||||
);
|
||||
foreach ($this->propertyMap as $key=>$field) $dat[$key] = $cal[$field];
|
||||
|
||||
$ret[] = $dat;
|
||||
if (!isset(self::$calendarCache[$calendarId])) {
|
||||
$c = q("SELECT * FROM %s%scalendars WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
self::$calendarCache[$calendarId] = $c[0];
|
||||
}
|
||||
return self::$calendarCache[$calendarId];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
/**
|
||||
* @static
|
||||
* @param int $obj_id
|
||||
* @return array
|
||||
*/
|
||||
static public function loadCalendarobjectById($obj_id)
|
||||
{
|
||||
if (!isset(self::$calendarObjectCache[$obj_id])) {
|
||||
$o = q("SELECT * FROM %s%scalendarobjects WHERE `id` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($obj_id)
|
||||
);
|
||||
self::$calendarObjectCache[$obj_id] = $o[0];
|
||||
}
|
||||
return self::$calendarObjectCache[$obj_id];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param Sabre_VObject_Component_VEvent $component
|
||||
* @return int
|
||||
*/
|
||||
public static function getDtEndTimeStamp(&$component)
|
||||
{
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $component->__get("DTSTART");
|
||||
if ($component->__get("DTEND")) {
|
||||
/** @var Sabre_VObject_Property_DateTime $dtend */
|
||||
$dtend = $component->__get("DTEND");
|
||||
return $dtend->getDateTime()->getTimeStamp();
|
||||
} elseif ($component->__get("DURATION")) {
|
||||
$endDate = clone $dtstart->getDateTime();
|
||||
$endDate->add(Sabre_VObject_DateTimeParser::parse($component->__get("DURATION")->value));
|
||||
return $endDate->getTimeStamp();
|
||||
} elseif ($dtstart->getDateType() === Sabre_VObject_Property_DateTime::DATE) {
|
||||
$endDate = clone $dtstart->getDateTime();
|
||||
$endDate->modify('+1 day');
|
||||
return $endDate->getTimeStamp();
|
||||
} else {
|
||||
return $dtstart->getDateTime()->getTimeStamp() + 3600;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses some information from calendar objects, used for optimized
|
||||
* calendar-queries.
|
||||
*
|
||||
* Returns an array with the following keys:
|
||||
* * etag
|
||||
* * size
|
||||
* * componentType
|
||||
* * firstOccurence
|
||||
* * lastOccurence
|
||||
*
|
||||
* @param string $calendarData
|
||||
* @throws Sabre_DAV_Exception_BadRequest
|
||||
* @return array
|
||||
*/
|
||||
protected function getDenormalizedData($calendarData)
|
||||
{
|
||||
/** @var Sabre_VObject_Component_VEvent $vObject */
|
||||
$vObject = Sabre_VObject_Reader::read($calendarData);
|
||||
$componentType = null;
|
||||
$component = null;
|
||||
$firstOccurence = null;
|
||||
$lastOccurence = null;
|
||||
foreach ($vObject->getComponents() as $component) {
|
||||
if ($component->name !== 'VTIMEZONE') {
|
||||
$componentType = $component->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$componentType) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
|
||||
}
|
||||
if ($componentType === 'VEVENT') {
|
||||
/** @var Sabre_VObject_Component_VEvent $component */
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $component->__get("DTSTART");
|
||||
$firstOccurence = $dtstart->getDateTime()->getTimeStamp();
|
||||
// Finding the last occurence is a bit harder
|
||||
if (!$component->__get("RRULE")) {
|
||||
$lastOccurence = self::getDtEndTimeStamp($component);
|
||||
} else {
|
||||
$it = new Sabre_VObject_RecurrenceIterator($vObject, (string)$component->__get("UID"));
|
||||
$maxDate = new DateTime(CALDAV_MAX_YEAR . "-01-01");
|
||||
if ($it->isInfinite()) {
|
||||
$lastOccurence = $maxDate->getTimeStamp();
|
||||
} else {
|
||||
$end = $it->getDtEnd();
|
||||
while ($it->valid() && $end < $maxDate) {
|
||||
$end = $it->getDtEnd();
|
||||
$it->next();
|
||||
|
||||
}
|
||||
$lastOccurence = $end->getTimeStamp();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'etag' => md5($calendarData),
|
||||
'size' => strlen($calendarData),
|
||||
'componentType' => $componentType,
|
||||
'firstOccurence' => $firstOccurence,
|
||||
'lastOccurence' => $lastOccurence,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,7 +204,8 @@ abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract
|
|||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateCalendar($calendarId, array $mutations) {
|
||||
public function updateCalendar($calendarId, array $mutations)
|
||||
{
|
||||
|
||||
$newValues = array();
|
||||
$result = array(
|
||||
|
@ -151,20 +247,33 @@ abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract
|
|||
|
||||
}
|
||||
|
||||
$x = explode("-", $calendarId);
|
||||
|
||||
$this->increaseCalendarCtag($x[0], $x[1]);
|
||||
$this->increaseCalendarCtag($calendarId);
|
||||
|
||||
$valuesSql = array();
|
||||
foreach ($newValues as $fieldName=> $value) $valuesSql[] = "`" . $fieldName . "` = '" . dbesc($value) . "'";
|
||||
if (count($valuesSql) > 0) {
|
||||
q("UPDATE %s%scalendars SET " . implode(", ", $valuesSql) . " WHERE `namespace` = %d AND `namespace_id` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1])
|
||||
);
|
||||
q("UPDATE %s%scalendars SET " . implode(", ", $valuesSql) . " WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $calendarId
|
||||
*/
|
||||
protected function increaseCalendarCtag($calendarId)
|
||||
{
|
||||
q("UPDATE %s%scalendars SET `ctag` = `ctag` + 1 WHERE `id` = '%d'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
self::$calendarObjectCache = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param int $calendar_id
|
||||
* @param int $calendarobject_id
|
||||
* @return string
|
||||
*/
|
||||
abstract function getItemDetailRedirect($calendar_id, $calendarobject_id);
|
||||
|
||||
}
|
495
dav/common/dav_caldav_backend_private.inc.php
Normal file
495
dav/common/dav_caldav_backend_private.inc.php
Normal file
|
@ -0,0 +1,495 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Backend_Private extends Sabre_CalDAV_Backend_Common
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var null|Sabre_CalDAV_Backend_Private
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return Sabre_CalDAV_Backend_Private
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (self::$instance == null) {
|
||||
self::$instance = new Sabre_CalDAV_Backend_Private();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return CALDAV_NAMESPACE_PRIVATE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @obsolete
|
||||
* @param array $calendar
|
||||
* @param int $user
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissionsCalendar($calendar, $user)
|
||||
{
|
||||
if ($calendar["namespace"] == CALDAV_NAMESPACE_PRIVATE && $user == $calendar["namespace_id"]) return array("read"=> true, "write"=> true);
|
||||
return array("read"=> false, "write"=> false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete
|
||||
* @param array $calendar
|
||||
* @param int $user
|
||||
* @param string $calendarobject_id
|
||||
* @param null|array $item_arr
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissionsItem($calendar, $user, $calendarobject_id, $item_arr = null)
|
||||
{
|
||||
return $this->getPermissionsCalendar($calendar, $user);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $row
|
||||
* @param array $calendar
|
||||
* @param string $base_path
|
||||
* @return array
|
||||
*/
|
||||
private function jqcal2wdcal($row, $calendar, $base_path)
|
||||
{
|
||||
$not = q("SELECT COUNT(*) num FROM %s%snotifications WHERE `calendar_id` = %d AND `calendarobject_id` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($row["calendar_id"]), IntVal($row["calendarobject_id"])
|
||||
);
|
||||
$editable = $this->getPermissionsItem($calendar["namespace_id"], $row["calendarobject_id"], $row);
|
||||
|
||||
$end = wdcal_mySql2PhpTime($row["EndTime"]);
|
||||
if ($row["IsAllDayEvent"]) $end -= 1;
|
||||
|
||||
return array(
|
||||
"jq_id" => $row["id"],
|
||||
"ev_id" => $row["calendarobject_id"],
|
||||
"summary" => escape_tags($row["Summary"]),
|
||||
"start" => wdcal_mySql2PhpTime($row["StartTime"]),
|
||||
"end" => $end,
|
||||
"is_allday" => $row["IsAllDayEvent"],
|
||||
"is_moredays" => 0,
|
||||
"is_recurring" => $row["IsRecurring"],
|
||||
"color" => (is_null($row["Color"]) || $row["Color"] == "" ? $calendar["calendarcolor"] : $row["Color"]),
|
||||
"is_editable" => ($editable ? 1 : 0),
|
||||
"is_editable_quick" => ($editable && !$row["IsRecurring"] ? 1 : 0),
|
||||
"location" => "Loc.",
|
||||
"attendees" => '',
|
||||
"has_notification" => ($not[0]["num"] > 0 ? 1 : 0),
|
||||
"url_detail" => $base_path . $row["calendarobject_id"] . "/",
|
||||
"url_edit" => $base_path . $row["calendarobject_id"] . "/edit/",
|
||||
"special_type" => "",
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $calendarId
|
||||
* @param string $sd
|
||||
* @param string $ed
|
||||
* @param string $base_path
|
||||
* @return array
|
||||
*/
|
||||
public function listItemsByRange($calendarId, $sd, $ed, $base_path)
|
||||
{
|
||||
$calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendarId);
|
||||
$von = wdcal_php2MySqlTime($sd);
|
||||
$bis = wdcal_php2MySqlTime($ed);
|
||||
|
||||
// @TODO Events, die früher angefangen haben, aber noch andauern
|
||||
$evs = q("SELECT * FROM %s%sjqcalendar WHERE `calendar_id` = %d AND `starttime` between '%s' and '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
|
||||
IntVal($calendarId), dbesc($von), dbesc($bis));
|
||||
|
||||
$events = array();
|
||||
foreach ($evs as $row) $events[] = $this->jqcal2wdcal($row, $calendar, $base_path . $row["calendar_id"] . "/");
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $calendar_id
|
||||
* @param int $calendarobject_id
|
||||
* @return string
|
||||
*/
|
||||
public function getItemDetailRedirect($calendar_id, $calendarobject_id)
|
||||
{
|
||||
return "/dav/wdcal/$calendar_id/$calendarobject_id/edit/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri)
|
||||
{
|
||||
$n = dav_compat_principal2namespace($principalUri);
|
||||
if ($n["namespace"] != $this->getNamespace()) return array();
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $this->getNamespace(), IntVal($n["namespace_id"]));
|
||||
$ret = array();
|
||||
foreach ($cals as $cal) {
|
||||
if (in_array($cal["uri"], $GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"])) continue;
|
||||
|
||||
$dat = array(
|
||||
"id" => $cal["id"],
|
||||
"uri" => $cal["uri"],
|
||||
"principaluri" => $principalUri,
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}getctag' => $cal['ctag'] ? $cal['ctag'] : '0',
|
||||
"calendar_class" => "Sabre_CalDAV_Calendar",
|
||||
);
|
||||
foreach ($this->propertyMap as $key=> $field) $dat[$key] = $cal[$field];
|
||||
|
||||
$ret[] = $dat;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws Sabre_DAV_Exception
|
||||
* @return string|void
|
||||
*/
|
||||
public function createCalendar($principalUri, $calendarUri, array $properties)
|
||||
{
|
||||
|
||||
$uid = dav_compat_principal2uid($principalUri);
|
||||
|
||||
$r = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, $uid, dbesc($calendarUri));
|
||||
if (count($r) > 0) throw new Sabre_DAV_Exception("A calendar with this URI already exists");
|
||||
|
||||
$keys = array("`namespace`", "`namespace_id`", "`ctag`", "`uri`");
|
||||
$vals = array(CALDAV_NAMESPACE_PRIVATE, IntVal($uid), 1, "'" . dbesc($calendarUri) . "'");
|
||||
|
||||
// Default value
|
||||
$sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
|
||||
$has_vevent = $has_vtodo = 1;
|
||||
if (isset($properties[$sccs])) {
|
||||
if (!($properties[$sccs] instanceof Sabre_CalDAV_Property_SupportedCalendarComponentSet)) {
|
||||
throw new Sabre_DAV_Exception('The ' . $sccs . ' property must be of type: Sabre_CalDAV_Property_SupportedCalendarComponentSet');
|
||||
}
|
||||
$v = $properties[$sccs]->getValue();
|
||||
$has_vevent = $has_vtodo = 0;
|
||||
foreach ($v as $w) {
|
||||
if (mb_strtolower($w) == "vevent") $has_vevent = 1;
|
||||
if (mb_strtolower($w) == "vtodo") $has_vtodo = 1;
|
||||
}
|
||||
}
|
||||
$keys[] = "`has_vevent`";
|
||||
$keys[] = "`has_vtodo`";
|
||||
$vals[] = $has_vevent;
|
||||
$vals[] = $has_vtodo;
|
||||
|
||||
foreach ($this->propertyMap as $xmlName=> $dbName) {
|
||||
if (isset($properties[$xmlName])) {
|
||||
$keys[] = "`$dbName`";
|
||||
$vals[] = "'" . dbesc($properties[$xmlName]) . "'";
|
||||
}
|
||||
}
|
||||
|
||||
$sql = sprintf("INSERT INTO %s%scalendars (" . implode(', ', $keys) . ") VALUES (" . implode(', ', $vals) . ")", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
|
||||
q($sql);
|
||||
|
||||
$x = q("SELECT id FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, $uid, $calendarUri
|
||||
);
|
||||
return $x[0]["id"];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties for a calendar.
|
||||
*
|
||||
* The mutations array uses the propertyName in clark-notation as key,
|
||||
* and the array value for the property value. In the case a property
|
||||
* should be deleted, the property value will be null.
|
||||
*
|
||||
* This method must be atomic. If one property cannot be changed, the
|
||||
* entire operation must fail.
|
||||
*
|
||||
* If the operation was successful, true can be returned.
|
||||
* If the operation failed, false can be returned.
|
||||
*
|
||||
* Deletion of a non-existent property is always successful.
|
||||
*
|
||||
* Lastly, it is optional to return detailed information about any
|
||||
* failures. In this case an array should be returned with the following
|
||||
* structure:
|
||||
*
|
||||
* array(
|
||||
* 403 => array(
|
||||
* '{DAV:}displayname' => null,
|
||||
* ),
|
||||
* 424 => array(
|
||||
* '{DAV:}owner' => null,
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* In this example it was forbidden to update {DAV:}displayname.
|
||||
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
|
||||
* (424 Failed Dependency) because the request needs to be atomic.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateCalendar($calendarId, array $mutations)
|
||||
{
|
||||
|
||||
$newValues = array();
|
||||
$result = array(
|
||||
200 => array(), // Ok
|
||||
403 => array(), // Forbidden
|
||||
424 => array(), // Failed Dependency
|
||||
);
|
||||
|
||||
$hasError = false;
|
||||
|
||||
foreach ($mutations as $propertyName=> $propertyValue) {
|
||||
|
||||
// We don't know about this property.
|
||||
if (!isset($this->propertyMap[$propertyName])) {
|
||||
$hasError = true;
|
||||
$result[403][$propertyName] = null;
|
||||
unset($mutations[$propertyName]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldName = $this->propertyMap[$propertyName];
|
||||
$newValues[$fieldName] = $propertyValue;
|
||||
|
||||
}
|
||||
|
||||
// If there were any errors we need to fail the request
|
||||
if ($hasError) {
|
||||
// Properties has the remaining properties
|
||||
foreach ($mutations as $propertyName=> $propertyValue) {
|
||||
$result[424][$propertyName] = null;
|
||||
}
|
||||
|
||||
// Removing unused statuscodes for cleanliness
|
||||
foreach ($result as $status=> $properties) {
|
||||
if (is_array($properties) && count($properties) === 0) unset($result[$status]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
$sql = "`ctag` = `ctag` + 1";
|
||||
foreach ($newValues as $key=> $val) $sql .= ", `" . $key . "` = '" . dbesc($val) . "'";
|
||||
|
||||
$sql = sprintf("UPDATE %s%scalendars SET $sql WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
|
||||
q($sql);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId)
|
||||
{
|
||||
q("DELETE FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
q("DELETE FROM %s%scalendars WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* * 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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
function getCalendarObjects($calendarId)
|
||||
{
|
||||
$objs = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
$ret = array();
|
||||
foreach ($objs as $obj) {
|
||||
$ret[] = array(
|
||||
"id" => IntVal($obj["id"]),
|
||||
"calendardata" => $obj["calendardata"],
|
||||
"uri" => $obj["uri"],
|
||||
"lastmodified" => $obj["lastmodified"],
|
||||
"calendarid" => $calendarId,
|
||||
"etag" => $obj["etag"],
|
||||
"size" => IntVal($obj["size"]),
|
||||
);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return array
|
||||
*/
|
||||
function getCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$o = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($objectUri));
|
||||
if (count($o) > 0) {
|
||||
$o[0]["calendarid"] = $calendarId;
|
||||
$o[0]["calendardata"] = str_ireplace("Europe/Belgrade", "Europe/Berlin", $o[0]["calendardata"]);
|
||||
return $o[0];
|
||||
} else throw new Sabre_DAV_Exception_NotFound($calendarId . " / " . $objectUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
function createCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
|
||||
$calendarData = icalendar_sanitize_string($calendarData);
|
||||
|
||||
$extraData = $this->getDenormalizedData($calendarData);
|
||||
|
||||
q("INSERT INTO %s%scalendarobjects (`calendar_id`, `uri`, `calendardata`, `lastmodified`, `componentType`, `firstOccurence`, `lastOccurence`, `etag`, `size`)
|
||||
VALUES (%d, '%s', '%s', NOW(), '%s', '%s', '%s', '%s', %d)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($objectUri), addslashes($calendarData), dbesc($extraData['componentType']),
|
||||
dbesc(wdcal_php2MySqlTime($extraData['firstOccurence'])), dbesc(wdcal_php2MySqlTime($extraData['lastOccurence'])), dbesc($extraData["etag"]), IntVal($extraData["size"])
|
||||
);
|
||||
|
||||
$this->increaseCalendarCtag($calendarId);
|
||||
renderCalDavEntry_uri($objectUri);
|
||||
|
||||
return '"' . $extraData['etag'] . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
function updateCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
$calendarData = icalendar_sanitize_string($calendarData);
|
||||
|
||||
$extraData = $this->getDenormalizedData($calendarData);
|
||||
|
||||
q("UPDATE %s%scalendarobjects SET `calendardata` = '%s', `lastmodified` = NOW(), `etag` = '%s', `size` = %d, `componentType` = '%s', `firstOccurence` = '%s', `lastOccurence` = '%s'
|
||||
WHERE `calendar_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($calendarData), dbesc($extraData["etag"]), IntVal($extraData["size"]), dbesc($extraData["componentType"]),
|
||||
dbesc(wdcal_php2MySqlTime($extraData["firstOccurence"])), dbesc(wdcal_php2MySqlTime($extraData["lastOccurence"])), IntVal($calendarId), dbesc($objectUri));
|
||||
|
||||
$this->increaseCalendarCtag($calendarId);
|
||||
renderCalDavEntry_uri($objectUri);
|
||||
|
||||
return '"' . $extraData['etag'] . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return void
|
||||
*/
|
||||
function deleteCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$r = q("SELECT `id` FROM %s%scalendarobjects WHERE `calendar_id` = %d AND `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($objectUri));
|
||||
if (count($r) == 0) throw new Sabre_DAV_Exception_NotFound();
|
||||
|
||||
q("DELETE FROM %s%scalendarobjects WHERE `calendar_id` = %d AND `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($objectUri));
|
||||
|
||||
$this->increaseCalendarCtag($calendarId);
|
||||
renderCalDavEntry_calobj_id($r[0]["id"]);
|
||||
}
|
||||
}
|
186
dav/common/dav_caldav_backend_virtual.inc.php
Normal file
186
dav/common/dav_caldav_backend_virtual.inc.php
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
|
||||
abstract class Sabre_CalDAV_Backend_Virtual extends Sabre_CalDAV_Backend_Common
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @abstract
|
||||
* @param int $calendarId
|
||||
* @param string $uri
|
||||
* @return array
|
||||
*/
|
||||
/*
|
||||
abstract public function getItemsByUri($calendarId, $uri);
|
||||
*/
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $uid
|
||||
* @param int $namespace
|
||||
*/
|
||||
static public function invalidateCache($uid = 0, $namespace = 0) {
|
||||
q("DELETE FROM %s%scal_virtual_object_sync WHERE `uid` = %d AND `namespace` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($uid), IntVal($namespace));
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @abstract
|
||||
* @param int $calendarId
|
||||
*/
|
||||
static abstract protected function createCache_internal($calendarId);
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $calendarId
|
||||
*/
|
||||
static protected function createCache($calendarId) {
|
||||
$calendarId = IntVal($calendarId);
|
||||
q("DELETE FROM %s%scal_virtual_object_cache WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId);
|
||||
static::createCache_internal($calendarId);
|
||||
q("REPLACE INTO %s%scal_virtual_object_sync (`calendar_id`, `date`) VALUES (%d, NOW())", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $calendarId
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObjects($calendarId)
|
||||
{
|
||||
$calendarId = IntVal($calendarId);
|
||||
$r = q("SELECT COUNT(*) n FROM %s%scal_virtual_object_sync WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId);
|
||||
|
||||
if ($r[0]["n"] == 0) static::createCache($calendarId);
|
||||
|
||||
$r = q("SELECT * FROM %s%scal_virtual_object_cache WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId);
|
||||
|
||||
$ret = array();
|
||||
foreach ($r as $obj) {
|
||||
$ret[] = array(
|
||||
"id" => IntVal($obj["data_uri"]),
|
||||
"calendardata" => $obj["calendardata"],
|
||||
"uri" => $obj["data_uri"],
|
||||
"lastmodified" => $obj["date"],
|
||||
"calendarid" => $calendarId,
|
||||
"etag" => $obj["etag"],
|
||||
"size" => IntVal($obj["size"]),
|
||||
);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$calendarId = IntVal($calendarId);
|
||||
$r = q("SELECT COUNT(*) n FROM %s%scal_virtual_object_sync WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
|
||||
if ($r[0]["n"] == 0) static::createCache($calendarId);
|
||||
|
||||
$r = q("SELECT * FROM %s%scal_virtual_object_cache WHERE `data_uri` = '%s' AND `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($objectUri), IntVal($calendarId));
|
||||
if (count($r) == 0) throw new Sabre_DAV_Exception_NotFound();
|
||||
|
||||
$obj = $r[0];
|
||||
$ret = array(
|
||||
"id" => IntVal($obj["data_uri"]),
|
||||
"calendardata" => $obj["calendardata"],
|
||||
"uri" => $obj["data_uri"],
|
||||
"lastmodified" => $obj["date"],
|
||||
"calendarid" => $calendarId,
|
||||
"etag" => $obj["etag"],
|
||||
"size" => IntVal($obj["size"]),
|
||||
);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function createCalendar($principalUri, $calendarUri, array $properties)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return null|string|void
|
||||
*/
|
||||
function createCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return null|string|void
|
||||
*/
|
||||
function updateCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
function deleteCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
|
||||
}
|
44
dav/common/dav_caldav_calendar_virtual.inc.php
Normal file
44
dav/common/dav_caldav_calendar_virtual.inc.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Calendar_Virtual extends Sabre_CalDAV_Calendar {
|
||||
|
||||
/**
|
||||
* Returns a list of ACE's for this node.
|
||||
*
|
||||
* Each ACE has the following properties:
|
||||
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||
* currently the only supported privileges
|
||||
* * 'principal', a url to the principal who owns the node
|
||||
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||
* be updated.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getACL() {
|
||||
|
||||
return array(
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}read-free-busy',
|
||||
'principal' => '{DAV:}authenticated',
|
||||
'protected' => true,
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
}
|
|
@ -14,6 +14,23 @@
|
|||
class Sabre_CardDAV_Backend_Std extends Sabre_CardDAV_Backend_Abstract
|
||||
{
|
||||
|
||||
/**
|
||||
* @var null|Sabre_CardDAV_Backend_Std
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return Sabre_CardDAV_Backend_Std
|
||||
*/
|
||||
public static function getInstance() {
|
||||
if (self::$instance == null) {
|
||||
self::$instance = new Sabre_CardDAV_Backend_Std();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the object
|
||||
*/
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The UserCalenders class contains all calendars associated to one user
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
|
||||
class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
|
@ -21,7 +13,7 @@ class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection
|
|||
/**
|
||||
* CalDAV backends
|
||||
*
|
||||
* @var array|Sabre_CalDAV_Backend_Abstract[]
|
||||
* @var array|Sabre_CalDAV_Backend_Common[]
|
||||
*/
|
||||
protected $caldavBackends;
|
||||
|
||||
|
@ -36,7 +28,7 @@ class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection
|
|||
* Constructor
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param array|Sabre_CalDAV_Backend_Abstract $caldavBackends
|
||||
* @param array|Sabre_CalDAV_Backend_Common[] $caldavBackends
|
||||
* @param mixed $userUri
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, $caldavBackends, $userUri) {
|
||||
|
@ -130,7 +122,7 @@ class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection
|
|||
* Returns a single calendar, by name
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Sabre_DAV_Exception_FileNotFound
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @todo needs optimizing
|
||||
* @return \Sabre_CalDAV_Calendar|\Sabre_DAV_INode
|
||||
*/
|
||||
|
@ -141,7 +133,7 @@ class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection
|
|||
return $child;
|
||||
|
||||
}
|
||||
throw new Sabre_DAV_Exception_FileNotFound('Calendar with name \'' . $name . '\' could not be found');
|
||||
throw new Sabre_DAV_Exception_NotFound('Calendar with name \'' . $name . '\' could not be found');
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -16,16 +16,19 @@ function wdcal_edit_getStartEnd() {
|
|||
|
||||
function wdcal_edit_checktime_startChanged() {
|
||||
"use strict";
|
||||
|
||||
var time = wdcal_edit_getStartEnd();
|
||||
if (time.start.getTime() >= time.end.getTime()) {
|
||||
var newend = new Date(time.start.getTime() + 3600000);
|
||||
$("#cal_end_date").datepicker("setDate", newend);
|
||||
$.timePicker("#cal_end_time").setTime(newend);
|
||||
}
|
||||
wdcal_edit_recur_recalc();
|
||||
}
|
||||
|
||||
function wdcal_edit_checktime_endChanged() {
|
||||
"use strict";
|
||||
|
||||
var time = wdcal_edit_getStartEnd();
|
||||
if (time.start.getTime() >= time.end.getTime()) {
|
||||
var newstart = new Date(time.end.getTime() - 3600000);
|
||||
|
@ -34,7 +37,27 @@ function wdcal_edit_checktime_endChanged() {
|
|||
}
|
||||
}
|
||||
|
||||
function wdcal_edit_init(dateFormat) {
|
||||
function wdcal_edit_recur_recalc() {
|
||||
"use strict";
|
||||
|
||||
var start = $("#cal_start_date").datepicker("getDate");
|
||||
$(".rec_month_name").text($.datepicker._defaults.monthNames[start.getMonth()]);
|
||||
$("#rec_yearly_day option[value=bymonthday], #rec_monthly_day option[value=bymonthday]").text($("#rec_yearly_day option[value=bymonthday]").data("orig").replace("#num#", start.getDate()));
|
||||
var month = new Date(start.getFullYear(), start.getMonth() + 1, 0);
|
||||
var monthlast = month.getDate() - start.getDate() + 1;
|
||||
$("#rec_yearly_day option[value=bymonthday_neg], #rec_monthly_day option[value=bymonthday_neg]").text($("#rec_yearly_day option[value=bymonthday_neg]").data("orig").replace("#num#", monthlast));
|
||||
var wk = Math.ceil(start.getDate() / 7);
|
||||
var wkname = $.datepicker._defaults.dayNames[start.getDay()];
|
||||
$("#rec_yearly_day option[value=byday], #rec_monthly_day option[value=byday]").text(
|
||||
$("#rec_yearly_day option[value=byday]").data("orig").replace("#num#", wk).replace("#wkday#", wkname)
|
||||
);
|
||||
var wk_inv = Math.ceil(monthlast / 7);
|
||||
$("#rec_yearly_day option[value=byday_neg], #rec_monthly_day option[value=byday_neg]").text(
|
||||
$("#rec_yearly_day option[value=byday_neg]").data("orig").replace("#num#", wk_inv).replace("#wkday#", wkname)
|
||||
);
|
||||
}
|
||||
|
||||
function wdcal_edit_init(dateFormat, base_path) {
|
||||
"use strict";
|
||||
|
||||
$("#cal_color").colorPicker();
|
||||
|
@ -49,6 +72,8 @@ function wdcal_edit_init(dateFormat) {
|
|||
"dateFormat": dateFormat
|
||||
}).on("change", wdcal_edit_checktime_endChanged);
|
||||
|
||||
$("#rec_until_date").datepicker({ "dateFormat": dateFormat });
|
||||
|
||||
$("#notification").on("click change", function() {
|
||||
if ($(this).prop("checked")) $("#notification_detail").show();
|
||||
else ($("#notification_detail")).hide();
|
||||
|
@ -58,4 +83,111 @@ function wdcal_edit_init(dateFormat) {
|
|||
if ($(this).prop("checked")) $("#cal_end_time, #cal_start_time").hide();
|
||||
else $("#cal_end_time, #cal_start_time").show();
|
||||
}).change();
|
||||
|
||||
$("#rec_frequency").on("click change", function() {
|
||||
var val = $("#rec_frequency").val();
|
||||
if (val == "") $("#rec_details").hide();
|
||||
else $("#rec_details").show();
|
||||
|
||||
if (val == "daily") $(".rec_daily").show();
|
||||
else $(".rec_daily").hide();
|
||||
|
||||
if (val == "weekly") $(".rec_weekly").show();
|
||||
else $(".rec_weekly").hide();
|
||||
|
||||
if (val == "monthly") $(".rec_monthly").show();
|
||||
else $(".rec_monthly").hide();
|
||||
|
||||
if (val == "yearly") $(".rec_yearly").show();
|
||||
else $(".rec_yearly").hide();
|
||||
}).change();
|
||||
|
||||
$("#rec_until_type").on("click change", function() {
|
||||
var val = $("#rec_until_type").val();
|
||||
|
||||
if (val == "count") $("#rec_until_count").show();
|
||||
else $("#rec_until_count").hide();
|
||||
|
||||
if (val == "date") $("#rec_until_date").show();
|
||||
else $("#rec_until_date").hide();
|
||||
}).change();
|
||||
|
||||
$("#rec_yearly_day option, #rec_monthly_day option").each(function() {
|
||||
$(this).data("orig", $(this).text());
|
||||
});
|
||||
|
||||
wdcal_edit_recur_recalc();
|
||||
|
||||
$(document).on("click", ".exception_remover", function(ev) {
|
||||
ev.preventDefault();
|
||||
var $this = $(this),
|
||||
$par = $this.parents(".rec_exceptions");
|
||||
$this.parents(".except").remove();
|
||||
if ($par.find(".rec_exceptions_holder").children().length == 0) {
|
||||
$par.find(".rec_exceptions_holder").hide();
|
||||
$par.find(".rec_exceptions_none").show();
|
||||
}
|
||||
});
|
||||
|
||||
$(".exception_adder").click(function(ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
var exceptions = [];
|
||||
$(".rec_exceptions .except input").each(function() {
|
||||
exceptions.push($(this).val());
|
||||
});
|
||||
var rec_weekly_byday = [];
|
||||
$(".rec_weekly_byday:checked").each(function() {
|
||||
rec_weekly_byday.push($(this).val());
|
||||
});
|
||||
var rec_daily_byday = [];
|
||||
$(".rec_daily_byday:checked").each(function() {
|
||||
rec_daily_byday.push($(this).val());
|
||||
});
|
||||
var opts = {
|
||||
"start_date": $("input[name=start_date]").val(),
|
||||
"start_time": $("input[name=start_time]").val(),
|
||||
"end_date": $("input[name=end_date]").val(),
|
||||
"end_time": $("input[name=end_time]").val(),
|
||||
"rec_frequency": $("#rec_frequency").val(),
|
||||
"rec_interval": $("#rec_interval").val(),
|
||||
"rec_until_type": $("#rec_until_type").val(),
|
||||
"rec_until_count": $("#rec_until_count").val(),
|
||||
"rec_until_date": $("#rec_until_date").val(),
|
||||
"rec_weekly_byday": rec_weekly_byday,
|
||||
"rec_daily_byday": rec_daily_byday,
|
||||
"rec_weekly_wkst": $("input[name=rec_weekly_wkst]:checked").val(),
|
||||
"rec_monthly_day": $("#rec_monthly_day").val(),
|
||||
"rec_yearly_day": $("#rec_yearly_day").val(),
|
||||
"rec_exceptions": exceptions
|
||||
};
|
||||
if ($("#cal_allday").prop("checked")) opts["allday"] = 1;
|
||||
var $dial = $("<div id='exception_setter_dialog'>Loading...</div>");
|
||||
$dial.appendTo("body");
|
||||
$dial.dialog({
|
||||
"width": 400,
|
||||
"height": 300,
|
||||
"title": "Exceptions"
|
||||
});
|
||||
$dial.load(base_path + "getExceptionDates/", opts, function() {
|
||||
$dial.find(".exception_selector_link").click(function(ev2) {
|
||||
ev2.preventDefault();
|
||||
var ts = $(this).data("timestamp");
|
||||
var str = $(this).html();
|
||||
var $part = $("<div data-timestamp='" + ts + "' class='except'><input type='hidden' class='rec_exception' name='rec_exceptions[]' value='" + ts + "'><a href='#' class='exception_remover'>[remove]</a> " + str + "</div>");
|
||||
var found = false;
|
||||
$(".rec_exceptions_holder .except").each(function() {
|
||||
if (!found && ts < $(this).data("timestamp")) {
|
||||
found = true;
|
||||
$part.insertBefore(this);
|
||||
}
|
||||
});
|
||||
if (!found) $(".rec_exceptions_holder").append($part);
|
||||
$(".rec_exceptions .rec_exceptions_holder").show();
|
||||
$(".rec_exceptions .rec_exceptions_none").hide();
|
||||
|
||||
$dial.dialog("destroy").remove();
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
|
@ -5,8 +5,10 @@
|
|||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
var __WDAY = new Array(i18n.xgcalendar.dateformat.sun, i18n.xgcalendar.dateformat.mon, i18n.xgcalendar.dateformat.tue, i18n.xgcalendar.dateformat.wed, i18n.xgcalendar.dateformat.thu, i18n.xgcalendar.dateformat.fri, i18n.xgcalendar.dateformat.sat);
|
||||
var __MonthName = new Array(i18n.xgcalendar.dateformat.jan, i18n.xgcalendar.dateformat.feb, i18n.xgcalendar.dateformat.mar, i18n.xgcalendar.dateformat.apr, i18n.xgcalendar.dateformat.may, i18n.xgcalendar.dateformat.jun, i18n.xgcalendar.dateformat.jul, i18n.xgcalendar.dateformat.aug, i18n.xgcalendar.dateformat.sep, i18n.xgcalendar.dateformat.oct, i18n.xgcalendar.dateformat.nov, i18n.xgcalendar.dateformat.dec);
|
||||
var __WDAY = $.datepicker._defaults.dayNamesShort;
|
||||
//new Array(i18n.xgcalendar.dateformat.sun, i18n.xgcalendar.dateformat.mon, i18n.xgcalendar.dateformat.tue, i18n.xgcalendar.dateformat.wed, i18n.xgcalendar.dateformat.thu, i18n.xgcalendar.dateformat.fri, i18n.xgcalendar.dateformat.sat);
|
||||
var __MonthName = $.datepicker._defaults.monthNamesShort;
|
||||
//new Array(i18n.xgcalendar.dateformat.jan, i18n.xgcalendar.dateformat.feb, i18n.xgcalendar.dateformat.mar, i18n.xgcalendar.dateformat.apr, i18n.xgcalendar.dateformat.may, i18n.xgcalendar.dateformat.jun, i18n.xgcalendar.dateformat.jul, i18n.xgcalendar.dateformat.aug, i18n.xgcalendar.dateformat.sep, i18n.xgcalendar.dateformat.oct, i18n.xgcalendar.dateformat.nov, i18n.xgcalendar.dateformat.dec);
|
||||
|
||||
|
||||
function dateFormat(format) {
|
||||
|
@ -769,8 +771,8 @@
|
|||
for (i = 0; i < l; i++) {
|
||||
var $col = $container.find(".tgCol" + i);
|
||||
for (var j = 0; j < events[i].length; j++) {
|
||||
if (events[i][j].event["color"] && events[i][j].event["color"].match(/^#[0-9a-f]{6}$/i)) {
|
||||
c = events[i][j].event["color"];
|
||||
if (events[i][j].event["color"] && events[i][j].event["color"].match(/^[0-9a-f]{6}$/i)) {
|
||||
c = "#" + events[i][j].event["color"];
|
||||
}
|
||||
else {
|
||||
c = option.std_color;
|
||||
|
@ -787,7 +789,7 @@
|
|||
function getTitle(event) {
|
||||
var timeshow, eventshow;
|
||||
var showtime = event["is_allday"] != 1;
|
||||
eventshow = event["subject"];
|
||||
eventshow = event["summary"];
|
||||
var startformat = getymformat(event["start"], null, showtime, true);
|
||||
var endformat = getymformat(event["end"], event["start"], showtime, true);
|
||||
timeshow = dateFormat.call(event["start"], startformat) + " - " + dateFormat.call(event["end"], endformat);
|
||||
|
@ -819,7 +821,7 @@
|
|||
var p = { bdcolor:theme[0], bgcolor2:theme[0], bgcolor1:theme[2], width:"70%", icon:"", title:"", data:"" };
|
||||
p.starttime = pZero(e.st.hour) + ":" + pZero(e.st.minute);
|
||||
p.endtime = pZero(e.et.hour) + ":" + pZero(e.et.minute);
|
||||
p.content = e.event["subject"];
|
||||
p.content = e.event["summary"];
|
||||
p.title = getTitle(e.event);
|
||||
var icons = [];
|
||||
if (e.event["has_notification"] == 1) icons.push("<I class=\"cic cic-tmr\"> </I>");
|
||||
|
@ -1146,12 +1148,12 @@
|
|||
var p = { color:theme[2], title:"", extendClass:"", extendHTML:"", data:"" };
|
||||
|
||||
p.title = getTitle(e.event);
|
||||
p.id = "bbit_cal_event_" + e.event["uri"];
|
||||
p.id = "bbit_cal_event_" + e.event["jq_id"];
|
||||
if (option.enableDrag && e.event["is_editable_quick"] == 1) {
|
||||
p.eclass = "drag";
|
||||
}
|
||||
else {
|
||||
p.eclass = "cal_" + e.event["uri"];
|
||||
p.eclass = "cal_" + e.event["jq_id"];
|
||||
}
|
||||
p.eclass += " " + (e.event["is_editable"] ? "editable" : "not_editable");
|
||||
var sp = "<span style=\"cursor: pointer\">{content}</span>";
|
||||
|
@ -1175,10 +1177,10 @@
|
|||
}
|
||||
var cen;
|
||||
if (!e.allday && !sf) {
|
||||
cen = pZero(e.st.hour) + ":" + pZero(e.st.minute) + " " + e.event["subject"];
|
||||
cen = pZero(e.st.hour) + ":" + pZero(e.st.minute) + " " + e.event["summary"];
|
||||
}
|
||||
else {
|
||||
cen = e.event["subject"];
|
||||
cen = e.event["summary"];
|
||||
}
|
||||
var content = [];
|
||||
if (cen.indexOf("Geburtstag:") == 0) {
|
||||
|
@ -1294,7 +1296,7 @@
|
|||
}
|
||||
if (option.eventItems[i]["start"] >= es) {
|
||||
for (var j = 0; j < jl; j++) {
|
||||
if (option.eventItems[i]["uri"] == events[j]["uri"] && option.eventItems[i]["start"] < start) {
|
||||
if (option.eventItems[i]["jq_id"] == events[j]["jq_id"] && option.eventItems[i]["start"] < start) {
|
||||
events.splice(j, 1); //for duplicated event
|
||||
jl--;
|
||||
break;
|
||||
|
@ -1477,7 +1479,7 @@
|
|||
$("#bbit-cs-buddle").css("visibility", "hidden");
|
||||
var calid = $("#bbit-cs-id").val();
|
||||
var param = [
|
||||
{ "name":"calendarId", value:calid },
|
||||
{ "name":"jq_id", value:calid },
|
||||
{ "name":"type", value:type}
|
||||
];
|
||||
var de = rebyKey(calid, true);
|
||||
|
@ -1609,8 +1611,8 @@
|
|||
var location = "";
|
||||
if (data["location"] != "") location = data["location"] + ", ";
|
||||
$("#bbit-cs-buddle-timeshow").html(location + ss.join(""));
|
||||
$bud.find(".bbit-cs-what").html(data["subject"]).attr("href", data["url_detail"]);
|
||||
$("#bbit-cs-id").val(data["uri"]);
|
||||
$bud.find(".bbit-cs-what").html(data["summary"]).attr("href", data["url_detail"]);
|
||||
$("#bbit-cs-id").val(data["jq_id"]);
|
||||
$bud.data("cdata", data);
|
||||
$bud.css({ "visibility":"visible", left:pos.left, top:pos.top });
|
||||
|
||||
|
@ -1684,11 +1686,11 @@
|
|||
return false;
|
||||
}
|
||||
option.isloading = true;
|
||||
var id = data["uri"];
|
||||
var id = data["jq_id"];
|
||||
var os = data["start"];
|
||||
var od = data["end"];
|
||||
var param = [
|
||||
{ "name":"calendarId", value:id },
|
||||
{ "name":"jq_id", value:id },
|
||||
{ "name":"CalendarStartTime", value:Math.floor(start.getTime() / 1000) },
|
||||
{ "name":"CalendarEndTime", value:Math.floor(end.getTime() / 1000) }
|
||||
];
|
||||
|
@ -1744,7 +1746,7 @@
|
|||
temparr.push('<table class="cb-table"><tbody><tr><th class="cb-key">');
|
||||
temparr.push(i18n.xgcalendar.time, ':</th><td class=cb-value><div id="bbit-cal-buddle-timeshow"></div></td></tr><tr><th class="cb-key">');
|
||||
temparr.push(i18n.xgcalendar.content, ':</th><td class="cb-value"><div class="textbox-fill-wrapper"><div class="textbox-fill-mid"><input id="bbit-cal-what" class="textbox-fill-input"/></div></div><div class="cb-example">');
|
||||
temparr.push(i18n.xgcalendar.example, '</div></td></tr></tbody></table><input id="bbit-cal-start" type="hidden"/><input id="bbit-cal-end" type="hidden"/><input id="bbit-cal-allday" type="hidden"/><input id="bbit-cal-quickAddBTN" value="');
|
||||
temparr.push(i18n.xgcalendar.example, '</div></td></tr></tbody></table><input id="bbit-cal-start" type="hidden"/><input id="bbit-cal-end" type="hidden"/><input id="bbit-cal-allday" type="hidden"/><input value="');
|
||||
temparr.push(i18n.xgcalendar.create_event, '" type="submit"/> <a href="" class="lk bbit-cal-editLink">');
|
||||
temparr.push(i18n.xgcalendar.update_detail, ' <StrONG>>></StrONG></SPAN></div></div></div><tr><td><div id="bl1" class="bubble-corner"><div class="bubble-sprite bubble-bl"></div></div><td><div class="bubble-bottom"></div><td><div id="br1" class="bubble-corner"><div class="bubble-sprite bubble-br"></div></div></tr></tbody></table><div id="bubbleClose1" class="bubble-closebutton"></div><div id="prong2" class="prong"><div class=bubble-sprite></div></div></div>');
|
||||
temparr.push('</form>');
|
||||
|
@ -1789,7 +1791,6 @@
|
|||
param[param.length] = option.extParam[pi];
|
||||
}
|
||||
}
|
||||
|
||||
if (option.quickAddHandler && $.isFunction(option.quickAddHandler)) {
|
||||
option.quickAddHandler.call(this, param);
|
||||
$("#bbit-cal-buddle").css("visibility", "hidden");
|
||||
|
@ -1804,8 +1805,9 @@
|
|||
ed = new Date(dateend),
|
||||
diff = DateDiff("d", sd, ed);
|
||||
var newdata = {
|
||||
"uri":"",
|
||||
"subject":what,
|
||||
"jq_id":"",
|
||||
"ev_id":"",
|
||||
"summary":what,
|
||||
"start":sd,
|
||||
"end":ed,
|
||||
"is_allday":(allday == "1" ? 1 : 0),
|
||||
|
@ -1886,7 +1888,7 @@
|
|||
var sl = option.eventItems.length;
|
||||
var i = -1;
|
||||
for (var j = 0; j < sl; j++) {
|
||||
if (option.eventItems[j]["uri"] == key) {
|
||||
if (option.eventItems[j]["jq_id"] == key) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
|
@ -2352,7 +2354,7 @@
|
|||
d.target.hide();
|
||||
ny = gP(gh.sh, gh.sm);
|
||||
d.top = ny;
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["subject"], false, false, data["color"]);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["summary"], false, false, data["color"]);
|
||||
cpwrap = $("<div class='ca-evpi drag-chip-wrapper' style='top:" + ny + "px'/>").html(tempdata);
|
||||
evid = ".tgOver" + d.target.parent().data("col");
|
||||
$gridcontainer.find(evid).append(cpwrap);
|
||||
|
@ -2389,7 +2391,7 @@
|
|||
//log.info("ny=" + ny);
|
||||
gh = gW(ny, ny + d.h);
|
||||
//log.info("sh=" + gh.sh + ",sm=" + gh.sm);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["subject"], false, false, data["color"]);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["summary"], false, false, data["color"]);
|
||||
d.cpwrap.css("top", ny + "px").html(tempdata);
|
||||
}
|
||||
d.ny = ny;
|
||||
|
@ -2415,7 +2417,7 @@
|
|||
d.target.hide();
|
||||
ny = gP(gh.sh, gh.sm);
|
||||
d.top = ny;
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["subject"], "100%", true, data["color"]);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["summary"], "100%", true, data["color"]);
|
||||
cpwrap = $("<div class='ca-evpi drag-chip-wrapper' style='top:" + ny + "px'/>").html(tempdata);
|
||||
evid = ".tgOver" + d.target.parent().data("col");
|
||||
$gridcontainer.find(evid).append(cpwrap);
|
||||
|
@ -2427,7 +2429,7 @@
|
|||
nh = pnh > 1 ? nh - pnh + Math.ceil(option.hour_height / 2) : nh - pnh;
|
||||
if (d.nh != nh) {
|
||||
gh = gW(d.top, d.top + nh);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["subject"], "100%", true, data["color"]);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["summary"], "100%", true, data["color"]);
|
||||
d.cpwrap.html(tempdata);
|
||||
}
|
||||
d.nh = nh;
|
||||
|
|
|
@ -7,26 +7,7 @@ var i18n = $.extend({}, i18n || {}, {
|
|||
"year_index": 2,
|
||||
"month_index": 1,
|
||||
"day_index": 0,
|
||||
"day": "d",
|
||||
"sun": "So",
|
||||
"mon": "Mo",
|
||||
"tue": "Di",
|
||||
"wed": "Mi",
|
||||
"thu": "Do",
|
||||
"fri": "Fr",
|
||||
"sat": "Sa",
|
||||
"jan": "Jan",
|
||||
"feb": "Feb",
|
||||
"mar": "Mär",
|
||||
"apr": "Apr",
|
||||
"may": "Mai",
|
||||
"jun": "Jun",
|
||||
"jul": "Jul",
|
||||
"aug": "Aug",
|
||||
"sep": "Sep",
|
||||
"oct": "Okt",
|
||||
"nov": "Nov",
|
||||
"dec": "Dez"
|
||||
"day": "d"
|
||||
},
|
||||
"no_implemented": "Nicht eingebaut",
|
||||
"to_date_view": "Zum aktuellen Datum gehen",
|
||||
|
|
|
@ -7,26 +7,7 @@ var i18n = $.extend({}, i18n || {}, {
|
|||
"year_index": 2,
|
||||
"month_index": 1,
|
||||
"day_index": 0,
|
||||
"day": "d",
|
||||
"sun": "Su",
|
||||
"mon": "Mo",
|
||||
"tue": "Tu",
|
||||
"wed": "Mi",
|
||||
"thu": "Th",
|
||||
"fri": "Fr",
|
||||
"sat": "Sa",
|
||||
"jan": "Jan",
|
||||
"feb": "Feb",
|
||||
"mar": "Mar",
|
||||
"apr": "Apr",
|
||||
"may": "May",
|
||||
"jun": "Jun",
|
||||
"jul": "Jul",
|
||||
"aug": "Aug",
|
||||
"sep": "Sep",
|
||||
"oct": "Oct",
|
||||
"nov": "Nov",
|
||||
"dec": "Dec"
|
||||
"day": "d"
|
||||
},
|
||||
"no_implemented": "Not implemented",
|
||||
"to_date_view": "Go to today",
|
||||
|
|
238
dav/common/wdcal_backend.inc.php
Normal file
238
dav/common/wdcal_backend.inc.php
Normal file
|
@ -0,0 +1,238 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $obj
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_jsonp_encode($obj)
|
||||
{
|
||||
$str = json_encode($obj);
|
||||
if (isset($_REQUEST["callback"])) {
|
||||
$str = $_REQUEST["callback"] . "(" . $str . ")";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $day
|
||||
* @param int $weekstartday
|
||||
* @param int $num_days
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
function wdcal_get_list_range_params($day, $weekstartday, $num_days, $type)
|
||||
{
|
||||
$phpTime = IntVal($day);
|
||||
switch ($type) {
|
||||
case "month":
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), 1, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime) + 1, 1, date("Y", $phpTime));
|
||||
break;
|
||||
case "week":
|
||||
//suppose first day of a week is monday
|
||||
$monday = date("d", $phpTime) - date('N', $phpTime) + 1;
|
||||
//echo date('N', $phpTime);
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), $monday, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), $monday + 7, date("Y", $phpTime));
|
||||
break;
|
||||
case "multi_days":
|
||||
//suppose first day of a week is monday
|
||||
$monday = date("d", $phpTime) - date('N', $phpTime) + $weekstartday;
|
||||
//echo date('N', $phpTime);
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), $monday, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), $monday + $num_days, date("Y", $phpTime));
|
||||
break;
|
||||
case "day":
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), date("d", $phpTime), date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), date("d", $phpTime) + 1, date("Y", $phpTime));
|
||||
break;
|
||||
default:
|
||||
return array(0, 0);
|
||||
}
|
||||
return array($st, $et);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param string $right
|
||||
* @return null|Sabre_CalDAV_Calendar
|
||||
*/
|
||||
function wdcal_print_feed_getCal(&$server, $right)
|
||||
{
|
||||
$cals = dav_get_current_user_calendars($server, $right);
|
||||
$calfound = null;
|
||||
for ($i = 0; $i < count($cals) && $calfound === null; $i++) {
|
||||
$prop = $cals[$i]->getProperties(array("id"));
|
||||
if (isset($prop["id"]) && (!isset($_REQUEST["cal"]) || in_array($prop["id"], $_REQUEST["cal"]))) $calfound = $cals[$i];
|
||||
}
|
||||
return $calfound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function wdcal_print_feed($base_path = "")
|
||||
{
|
||||
$server = dav_create_server(true, true, false);
|
||||
|
||||
$ret = null;
|
||||
|
||||
$method = $_GET["method"];
|
||||
switch ($method) {
|
||||
case "add":
|
||||
$cs = wdcal_print_feed_getCal($server, DAV_ACL_WRITE);
|
||||
if ($cs == null) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
try {
|
||||
$item = dav_create_empty_vevent();
|
||||
$component = dav_get_eventComponent($item);
|
||||
$component->add("SUMMARY", icalendar_sanitize_string(dav_compat_parse_text_serverside("CalendarTitle")));
|
||||
|
||||
if (isset($_REQUEST["allday"])) $type = Sabre_VObject_Property_DateTime::DATE;
|
||||
else $type = Sabre_VObject_Property_DateTime::LOCALTZ;
|
||||
|
||||
$datetime_start = new Sabre_VObject_Property_DateTime("DTSTART");
|
||||
$datetime_start->setDateTime(new DateTime(date("Y-m-d H:i:s", IntVal($_REQUEST["CalendarStartTime"]))), $type);
|
||||
$datetime_end = new Sabre_VObject_Property_DateTime("DTEND");
|
||||
$datetime_end->setDateTime(new DateTime(date("Y-m-d H:i:s", IntVal($_REQUEST["CalendarEndTime"]))), $type);
|
||||
|
||||
$component->add($datetime_start);
|
||||
$component->add($datetime_end);
|
||||
|
||||
$uid = $component->__get("UID");
|
||||
$data = $item->serialize();
|
||||
|
||||
$cs->createFile($uid . ".ics", $data);
|
||||
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'add success',
|
||||
'Data' => $uid . ".ics",
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$ret = array(
|
||||
'IsSuccess' => false,
|
||||
'Msg' => $e->__toString(),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "list":
|
||||
$weekstartday = (isset($_REQUEST["weekstartday"]) ? IntVal($_REQUEST["weekstartday"]) : 1); // 1 = Monday
|
||||
$num_days = (isset($_REQUEST["num_days"]) ? IntVal($_REQUEST["num_days"]) : 7);
|
||||
$ret = null;
|
||||
|
||||
$date = wdcal_get_list_range_params($_REQUEST["showdate"], $weekstartday, $num_days, $_REQUEST["viewtype"]);
|
||||
$ret = array();
|
||||
$ret['events'] = array();
|
||||
$ret["issort"] = true;
|
||||
$ret["start"] = $date[0];
|
||||
$ret["end"] = $date[1];
|
||||
$ret['error'] = null;
|
||||
|
||||
$cals = dav_get_current_user_calendars($server, DAV_ACL_READ);
|
||||
foreach ($cals as $cal) {
|
||||
$prop = $cal->getProperties(array("id"));
|
||||
if (isset($prop["id"]) && (!isset($_REQUEST["cal"]) || in_array($prop["id"], $_REQUEST["cal"]))) {
|
||||
$backend = wdcal_calendar_factory_by_id($prop["id"]);
|
||||
$events = $backend->listItemsByRange($prop["id"], $date[0], $date[1], $base_path);
|
||||
$ret["events"] = array_merge($ret["events"], $events);
|
||||
}
|
||||
}
|
||||
|
||||
$tmpev = array();
|
||||
foreach ($ret["events"] as $e) {
|
||||
if (!isset($tmpev[$e["start"]])) $tmpev[$e["start"]] = array();
|
||||
$tmpev[$e["start"]][] = $e;
|
||||
}
|
||||
ksort($tmpev);
|
||||
$ret["events"] = array();
|
||||
foreach ($tmpev as $e) foreach ($e as $f) $ret["events"][] = $f;
|
||||
|
||||
break;
|
||||
case "update":
|
||||
$r = q("SELECT `calendarobject_id`, `calendar_id` FROM %s%sjqcalendar WHERE `id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["jq_id"]));
|
||||
if (count($r) != 1) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
try {
|
||||
$cs = dav_get_current_user_calendar_by_id($server, $r[0]["calendar_id"], DAV_ACL_READ);
|
||||
$obj_uri = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($r[0]["calendarobject_id"]);
|
||||
|
||||
$vObject = dav_get_current_user_calendarobject($server, $cs, $obj_uri["uri"], DAV_ACL_WRITE);
|
||||
$component = dav_get_eventComponent($vObject);
|
||||
|
||||
if (!$component) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
|
||||
if (isset($_REQUEST["allday"])) $type = Sabre_VObject_Property_DateTime::DATE;
|
||||
else $type = Sabre_VObject_Property_DateTime::LOCALTZ;
|
||||
|
||||
$datetime_start = new Sabre_VObject_Property_DateTime("DTSTART");
|
||||
$datetime_start->setDateTime(new DateTime(date("Y-m-d H:i:s", IntVal($_REQUEST["CalendarStartTime"]))), $type);
|
||||
$datetime_end = new Sabre_VObject_Property_DateTime("DTEND");
|
||||
$datetime_end->setDateTime(new DateTime(date("Y-m-d H:i:s", IntVal($_REQUEST["CalendarEndTime"]))), $type);
|
||||
|
||||
$component->__unset("DTSTART");
|
||||
$component->__unset("DTEND");
|
||||
$component->add($datetime_start);
|
||||
$component->add($datetime_end);
|
||||
|
||||
$data = $vObject->serialize();
|
||||
/** @var Sabre_CalDAV_CalendarObject $child */
|
||||
$child = $cs->getChild($obj_uri["uri"]);
|
||||
$child->put($data);
|
||||
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'Succefully',
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
break;
|
||||
case "remove":
|
||||
$r = q("SELECT `calendarobject_id`, `calendar_id` FROM %s%sjqcalendar WHERE `id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["jq_id"]));
|
||||
if (count($r) != 1) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
try {
|
||||
$cs = dav_get_current_user_calendar_by_id($server, $r[0]["calendar_id"], DAV_ACL_WRITE);
|
||||
$obj_uri = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($r[0]["calendarobject_id"]);
|
||||
$child = $cs->getChild($obj_uri["uri"]);
|
||||
$child->delete();
|
||||
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'Succefully',
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
echo wdcal_jsonp_encode($ret);
|
||||
killme();
|
||||
}
|
||||
|
|
@ -40,6 +40,13 @@ abstract class wdcal_local
|
|||
return $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @abstract
|
||||
* @return string
|
||||
*/
|
||||
abstract static function getLanguageCode();
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @static
|
||||
|
@ -77,6 +84,13 @@ abstract class wdcal_local
|
|||
*/
|
||||
abstract function date_timestamp2local($ts);
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param int $ts
|
||||
* @return string
|
||||
*/
|
||||
abstract function date_timestamp2localDate($ts);
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @return int
|
||||
|
@ -119,6 +133,14 @@ abstract class wdcal_local
|
|||
|
||||
class wdcal_local_us extends wdcal_local {
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return string
|
||||
*/
|
||||
static function getLanguageCode() {
|
||||
return "en";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@ -152,6 +174,14 @@ class wdcal_local_us extends wdcal_local {
|
|||
return date("m/d/Y H:i", $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $ts
|
||||
* @return string
|
||||
*/
|
||||
function date_timestamp2localDate($ts) {
|
||||
return date("l, F jS Y", $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
|
@ -198,6 +228,14 @@ class wdcal_local_us extends wdcal_local {
|
|||
|
||||
class wdcal_local_de extends wdcal_local {
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return string
|
||||
*/
|
||||
static function getLanguageCode() {
|
||||
return "de";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@ -231,6 +269,14 @@ class wdcal_local_de extends wdcal_local {
|
|||
return date("d.m.Y H:i", $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $ts
|
||||
* @return string
|
||||
*/
|
||||
function date_timestamp2localDate($ts) {
|
||||
return date("l, j. F Y", $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
|
|
510
dav/common/wdcal_edit.inc.php
Normal file
510
dav/common/wdcal_edit.inc.php
Normal file
|
@ -0,0 +1,510 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @param wdcal_local $localization
|
||||
* @param string $baseurl
|
||||
* @param int $uid
|
||||
* @param int $calendar_id
|
||||
* @param int $uri
|
||||
* @param string $recurr_uri
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_getEditPage_str(&$localization, $baseurl, $uid, $calendar_id, $uri, $recurr_uri = "")
|
||||
{
|
||||
$server = dav_create_server(true, true, false);
|
||||
|
||||
if ($uri > 0) {
|
||||
$calendar = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_WRITE);
|
||||
if (!$calendar) {
|
||||
$calendar = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_READ);
|
||||
$calendars = array();
|
||||
} else {
|
||||
$calendars = dav_get_current_user_calendars($server, DAV_ACL_WRITE);
|
||||
}
|
||||
|
||||
if ($calendar == null) return "Calendar not found";
|
||||
|
||||
$obj_uri = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($uri);
|
||||
|
||||
$vObject = dav_get_current_user_calendarobject($server, $calendar, $obj_uri["uri"], DAV_ACL_WRITE);
|
||||
$component = dav_get_eventComponent($vObject);
|
||||
|
||||
if ($component == null) return t('Could not open component for editing');
|
||||
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $component->__get("DTSTART");
|
||||
$event = array(
|
||||
"id" => IntVal($uri),
|
||||
"Summary" => ($component->__get("SUMMARY") ? $component->__get("SUMMARY")->value : null),
|
||||
"StartTime" => $dtstart->getDateTime()->getTimeStamp(),
|
||||
"EndTime" => Sabre_CalDAV_Backend_Common::getDtEndTimeStamp($component),
|
||||
"IsAllDayEvent" => (strlen($dtstart->value) == 8),
|
||||
"Description" => ($component->__get("DESCRIPTION") ? $component->__get("DESCRIPTION")->value : null),
|
||||
"Location" => ($component->__get("LOCATION") ? $component->__get("LOCATION")->value : null),
|
||||
"Color" => ($component->__get("X-ANIMEXX-COLOR") ? $component->__get("X-ANIMEXX-COLOR")->value : null),
|
||||
);
|
||||
|
||||
$exdates = $component->select("EXDATE");
|
||||
$recurrentce_exdates = array();
|
||||
/** @var Sabre_VObject_Property_MultiDateTime $x */
|
||||
foreach ($exdates as $x) {
|
||||
/** @var DateTime $y */
|
||||
$z = $x->getDateTimes();
|
||||
foreach ($z as $y) $recurrentce_exdates[] = $y->getTimeStamp();
|
||||
}
|
||||
|
||||
if ($component->select("RRULE")) $recurrence = new Sabre_VObject_RecurrenceIterator($vObject, (string)$component->__get("UID"));
|
||||
else $recurrence = null;
|
||||
|
||||
} elseif (isset($_REQUEST["start"]) && $_REQUEST["start"] > 0) {
|
||||
$calendars = dav_get_current_user_calendars($server, DAV_ACL_WRITE);
|
||||
$calendar = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_WRITE);
|
||||
|
||||
$event = array(
|
||||
"id" => 0,
|
||||
"Summary" => $_REQUEST["title"],
|
||||
"StartTime" => InTVal($_REQUEST["start"]),
|
||||
"EndTime" => IntVal($_REQUEST["end"]),
|
||||
"IsAllDayEvent" => $_REQUEST["isallday"],
|
||||
"Description" => "",
|
||||
"Location" => "",
|
||||
"Color" => "#5858ff",
|
||||
);
|
||||
if ($_REQUEST["isallday"]) {
|
||||
$notifications = array(array("rel" => "start", "type" => "duration", "period" => "hour", "period_val" => 24));
|
||||
} else {
|
||||
$notifications = array(array("rel" => "start", "type" => "duration", "period" => "hour", "period_val" => 1));
|
||||
}
|
||||
$recurrence = null;
|
||||
$recurrentce_exdates = array();
|
||||
} else {
|
||||
$calendars = dav_get_current_user_calendars($server, DAV_ACL_WRITE);
|
||||
$calendar = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_WRITE);
|
||||
|
||||
$event = array(
|
||||
"id" => 0,
|
||||
"Summary" => "",
|
||||
"StartTime" => time(),
|
||||
"EndTime" => time() + 3600,
|
||||
"IsAllDayEvent" => "0",
|
||||
"Description" => "",
|
||||
"Location" => "",
|
||||
"Color" => "#5858ff",
|
||||
);
|
||||
$notifications = array(array("rel" => "start", "type" => "duration", "period" => "hour", "period_val" => 1));
|
||||
$recurrence = null;
|
||||
$recurrentce_exdates = array();
|
||||
}
|
||||
|
||||
$postto = $baseurl . "/dav/wdcal/" . ($uri == 0 ? "new/" : $calendar_id . "/" . $uri . "/edit/");
|
||||
|
||||
$out = "<a href='" . $baseurl . "/dav/wdcal/'>" . t("Go back to the calendar") . "</a><br><br>";
|
||||
$out .= "<form method='POST' action='$postto'>
|
||||
<input type='hidden' name='form_security_token' value='" . get_form_security_token('caledit') . "'>\n";
|
||||
|
||||
$out .= "<h2>" .t("Event data") . "</h2>";
|
||||
|
||||
$out .= "<label for='calendar'>" . t("Calendar") . ":</label><select name='calendar' size='1'>";
|
||||
foreach ($calendars as $cal) {
|
||||
$prop = $cal->getProperties(array("id", DAV_DISPLAYNAME));
|
||||
$out .= "<option value='" . $prop["id"] . "' ";
|
||||
if ($prop["id"] == $calendar_id) $out .= "selected";
|
||||
$out .= ">" . escape_tags($prop[DAV_DISPLAYNAME]) . "</option>\n";
|
||||
}
|
||||
$out .= "</select><br>\n";
|
||||
|
||||
$out .= "<label class='block' for='cal_summary'>" . t("Subject") . ":</label>
|
||||
<input name='color' id='cal_color' value='" . (strlen($event["Color"]) != 7 ? "#5858ff" : escape_tags($event["Color"])) . "'>
|
||||
<input name='summary' id='cal_summary' value='" . escape_tags($event["Summary"]) . "'><br>\n";
|
||||
$out .= "<label class='block' for='cal_allday'>Is All-Day event:</label><input type='checkbox' name='allday' id='cal_allday' " . ($event["IsAllDayEvent"] ? "checked" : "") . "><br>\n";
|
||||
|
||||
$out .= "<label class='block' for='cal_startdate'>" . t("Starts") . ":</label>";
|
||||
$out .= "<input name='start_date' value='" . $localization->dateformat_datepicker_php($event["StartTime"]) . "' id='cal_start_date'>";
|
||||
$out .= "<input name='start_time' value='" . date("H:i", $event["StartTime"]) . "' id='cal_start_time'>";
|
||||
$out .= "<br>\n";
|
||||
|
||||
$out .= "<label class='block' for='cal_enddate'>" . t("Ends") . ":</label>";
|
||||
$out .= "<input name='end_date' value='" . $localization->dateformat_datepicker_php($event["EndTime"]) . "' id='cal_end_date'>";
|
||||
$out .= "<input name='end_time' value='" . date("H:i", $event["EndTime"]) . "' id='cal_end_time'>";
|
||||
$out .= "<br>\n";
|
||||
|
||||
$out .= "<label class='block' for='cal_location'>" . t("Location") . ":</label><input name='location' id='cal_location' value='" . escape_tags($event["Location"]) . "'><br>\n";
|
||||
|
||||
$out .= "<label class='block' for='event-desc-textarea'>" . t("Description") . ":</label> <textarea id='event-desc-textarea' name='wdcal_desc' style='vertical-align: top; width: 400px; height: 100px;'>" . escape_tags($event["Description"]) . "</textarea>";
|
||||
$out .= "<br style='clear: both;'>";
|
||||
|
||||
$out .= "<h2>" .t("Recurrence") . "</h2>";
|
||||
|
||||
$out .= "<label class='block' for='rec_frequency'>" . t("Frequency") . ":</label> <select id='rec_frequency' name='rec_frequency' size='1'>";
|
||||
$out .= "<option value=''>" . t("None") . "</option>\n";
|
||||
$out .= "<option value='daily' "; if ($recurrence && $recurrence->frequency == "daily") $out .= "selected"; $out .= ">" . t("Daily") . "</option>\n";
|
||||
$out .= "<option value='weekly' "; if ($recurrence && $recurrence->frequency == "weekly") $out .= "selected"; $out .= ">" . t("Weekly") . "</option>\n";
|
||||
$out .= "<option value='monthly' "; if ($recurrence && $recurrence->frequency == "monthly") $out .= "selected"; $out .= ">" . t("Monthly") . "</option>\n";
|
||||
$out .= "<option value='yearly' "; if ($recurrence && $recurrence->frequency == "yearly") $out .= "selected"; $out .= ">" . t("Yearly") . "</option>\n";
|
||||
$out .="</select><br>\n";
|
||||
$out .= "<div id='rec_details'>";
|
||||
|
||||
$select = "<select id='rec_interval' name='rec_interval' size='1'>";
|
||||
for ($i = 1; $i < 50; $i++) {
|
||||
$select .= "<option value='$i' ";
|
||||
if ($recurrence && $i == $recurrence->interval) $select .= "selected";
|
||||
$select .= ">$i</option>\n";
|
||||
}
|
||||
$select .= "</select>";
|
||||
$time = "<span class='rec_daily'>" . t("days") . "</span>";
|
||||
$time .= "<span class='rec_weekly'>" . t("weeks") . "</span>";
|
||||
$time .= "<span class='rec_monthly'>" . t("months") . "</span>";
|
||||
$time .= "<span class='rec_yearly'>" . t("years") . "</span>";
|
||||
$out .= "<label class='block' for='rev_interval'>" . t("Interval") . ":</label> " . str_replace(array("%select%", "%time%"), array($select, $time), t("All %select% %time%")) . "<br>";
|
||||
|
||||
|
||||
$out .= "<div class='rec_daily'>";
|
||||
$out .= "<label class='block'>" . t("Days") . ":</label>";
|
||||
if ($recurrence && $recurrence->byDay) {
|
||||
$byday = $recurrence->byDay;
|
||||
} else {
|
||||
$byday = array("MO", "TU", "WE", "TH", "FR", "SA", "SU");
|
||||
}
|
||||
if ($localization->getFirstDayOfWeek() == 0) {
|
||||
$out .= "<label class='plain'><input class='rec_daily_byday' type='checkbox' name='rec_daily_byday[]' value='SU' "; if (in_array("SU", $byday)) $out .= "checked"; $out .= ">" . t("Sunday") . "</label> ";
|
||||
}
|
||||
$out .= "<label class='plain'><input class='rec_daily_byday' type='checkbox' name='rec_daily_byday[]' value='MO' "; if (in_array("MO", $byday)) $out .= "checked"; $out .= ">" . t("Monday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_daily_byday' type='checkbox' name='rec_daily_byday[]' value='TU' "; if (in_array("TU", $byday)) $out .= "checked"; $out .= ">" . t("Tuesday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_daily_byday' type='checkbox' name='rec_daily_byday[]' value='WE' "; if (in_array("WE", $byday)) $out .= "checked"; $out .= ">" . t("Wednesday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_daily_byday' type='checkbox' name='rec_daily_byday[]' value='TH' "; if (in_array("TH", $byday)) $out .= "checked"; $out .= ">" . t("Thursday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_daily_byday' type='checkbox' name='rec_daily_byday[]' value='FR' "; if (in_array("FR", $byday)) $out .= "checked"; $out .= ">" . t("Friday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_daily_byday' type='checkbox' name='rec_daily_byday[]' value='SA' "; if (in_array("SA", $byday)) $out .= "checked"; $out .= ">" . t("Saturday") . "</label> ";
|
||||
if ($localization->getFirstDayOfWeek() != 0) {
|
||||
$out .= "<label class='plain'><input class='rec_daily_byday' type='checkbox' name='rec_daily_byday[]' value='SU' "; if (in_array("SU", $byday)) $out .= "checked"; $out .= ">" . t("Sunday") . "</label> ";
|
||||
}
|
||||
$out .= "</div>";
|
||||
|
||||
|
||||
$out .= "<div class='rec_weekly'>";
|
||||
$out .= "<label class='block'>" . t("Days") . ":</label>";
|
||||
if ($recurrence && $recurrence->byDay) {
|
||||
$byday = $recurrence->byDay;
|
||||
} else {
|
||||
$byday = array("MO", "TU", "WE", "TH", "FR", "SA", "SU");
|
||||
}
|
||||
if ($localization->getFirstDayOfWeek() == 0) {
|
||||
$out .= "<label class='plain'><input class='rec_weekly_byday' type='checkbox' name='rec_weekly_byday[]' value='SU' "; if (in_array("SU", $byday)) $out .= "checked"; $out .= ">" . t("Sunday") . "</label> ";
|
||||
}
|
||||
$out .= "<label class='plain'><input class='rec_weekly_byday' type='checkbox' name='rec_weekly_byday[]' value='MO' "; if (in_array("MO", $byday)) $out .= "checked"; $out .= ">" . t("Monday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_weekly_byday' type='checkbox' name='rec_weekly_byday[]' value='TU' "; if (in_array("TU", $byday)) $out .= "checked"; $out .= ">" . t("Tuesday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_weekly_byday' type='checkbox' name='rec_weekly_byday[]' value='WE' "; if (in_array("WE", $byday)) $out .= "checked"; $out .= ">" . t("Wednesday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_weekly_byday' type='checkbox' name='rec_weekly_byday[]' value='TH' "; if (in_array("TH", $byday)) $out .= "checked"; $out .= ">" . t("Thursday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_weekly_byday' type='checkbox' name='rec_weekly_byday[]' value='FR' "; if (in_array("FR", $byday)) $out .= "checked"; $out .= ">" . t("Friday") . "</label> ";
|
||||
$out .= "<label class='plain'><input class='rec_weekly_byday' type='checkbox' name='rec_weekly_byday[]' value='SA' "; if (in_array("SA", $byday)) $out .= "checked"; $out .= ">" . t("Saturday") . "</label> ";
|
||||
if ($localization->getFirstDayOfWeek() != 0) {
|
||||
$out .= "<label class='plain'><input class='rec_weekly_byday' type='checkbox' name='rec_weekly_byday[]' value='SU' "; if (in_array("SU", $byday)) $out .= "checked"; $out .= ">" . t("Sunday") . "</label> ";
|
||||
}
|
||||
$out .= "<br>";
|
||||
|
||||
$out .= "<label class='block'>" . t("First day of week:") . "</label>";
|
||||
if ($recurrence && $recurrence->weekStart != "") $wkst = $recurrence->weekStart;
|
||||
else {
|
||||
if ($localization->getFirstDayOfWeek() == 0) $wkst = "SU";
|
||||
else $wkst = "MO";
|
||||
}
|
||||
$out .= "<label class='plain'><input type='radio' name='rec_weekly_wkst' value='SU' "; if ($wkst == "SU") $out .= "checked"; $out .= ">" . t("Sunday") . "</label> ";
|
||||
$out .= "<label class='plain'><input type='radio' name='rec_weekly_wkst' value='MO' "; if ($wkst == "MO") $out .= "checked"; $out .= ">" . t("Monday") . "</label><br>\n";
|
||||
|
||||
$out .= "</div>";
|
||||
|
||||
$monthly_rule = "bymonthday"; // @TODO
|
||||
$out .= "<div class='rec_monthly'>";
|
||||
$out .= "<label class='block' name='rec_monthly_day'>" . t("Day of month") . ":</label>";
|
||||
$out .= "<select id='rec_monthly_day' name='rec_monthly_day' size='1'>";
|
||||
$out .= "<option value='bymonthday' "; if ($monthly_rule == "bymonthday") $out .= "selected"; $out .= ">" . t("#num#th of each month") . "</option>\n";
|
||||
$out .= "<option value='bymonthday_neg' "; if ($monthly_rule == "bymonthday_neg") $out .= "selected"; $out .= ">" . t("#num#th-last of each month") . "</option>\n";
|
||||
$out .= "<option value='byday' "; if ($monthly_rule == "byday") $out .= "selected"; $out .= ">" . t("#num#th #wkday# of each month") . "</option>\n";
|
||||
$out .= "<option value='byday_neg' "; if ($monthly_rule == "byday_neg") $out .= "selected"; $out .= ">" . t("#num#th-last #wkday# of each month") . "</option>\n";
|
||||
$out .= "</select>";
|
||||
$out .= "</div>\n";
|
||||
|
||||
|
||||
$out .= "<div class='rec_yearly'>";
|
||||
$out .= "<label class='block' name='rec_yearly_day'>" . t("Month") . ":</label> <span class='rec_month_name'>#month#</span><br>\n";
|
||||
$out .= "<label class='block' name='rec_yearly_day'>" . t("Day of month") . ":</label>";
|
||||
$out .= "<select id='rec_yearly_day' name='rec_yearly_day' size='1'>";
|
||||
$out .= "<option value='bymonthday' "; if ($monthly_rule == "bymonthday") $out .= "selected"; $out .= ">" . t("#num#th of each month") . "</option>\n";
|
||||
$out .= "<option value='bymonthday_neg' "; if ($monthly_rule == "bymonthday_neg") $out .= "selected"; $out .= ">" . t("#num#th-last of each month") . "</option>\n";
|
||||
$out .= "<option value='byday' "; if ($monthly_rule == "byday") $out .= "selected"; $out .= ">" . t("#num#th #wkday# of each month") . "</option>\n";
|
||||
$out .= "<option value='byday_neg' "; if ($monthly_rule == "byday_neg") $out .= "selected"; $out .= ">" . t("#num#th-last #wkday# of each month") . "</option>\n";
|
||||
$out .= "</select>";
|
||||
$out .= "</div>\n";
|
||||
|
||||
|
||||
if ($recurrence) {
|
||||
$until = $recurrence->until;
|
||||
$count = $recurrence->count;
|
||||
if (is_a($until, "DateTime")) {
|
||||
/** @var DateTime $until */
|
||||
$rule_type = "date";
|
||||
$rule_until_date = $until->getTimestamp();
|
||||
$rule_until_count = 1;
|
||||
} elseif ($count > 0) {
|
||||
$rule_type = "count";
|
||||
$rule_until_date = time();
|
||||
$rule_until_count = $count;
|
||||
} else {
|
||||
$rule_type = "infinite";
|
||||
$rule_until_date = time();
|
||||
$rule_until_count = 1;
|
||||
}
|
||||
} else {
|
||||
$rule_type = "infinite";
|
||||
$rule_until_date = time();
|
||||
$rule_until_count = 1;
|
||||
}
|
||||
$out .= "<label class='block' for='rec_until_type'>" . t("Repeat until") . ":</label> ";
|
||||
$out .= "<select name='rec_until_type' id='rec_until_type' size='1'>";
|
||||
$out .= "<option value='infinite' "; if ($rule_type == "infinite") $out .= "selected"; $out .= ">" . t("Infinite") . "</option>\n";
|
||||
$out .= "<option value='date' "; if ($rule_type == "date") $out .= "selected"; $out .= ">" . t("Until the following date") . ":</option>\n";
|
||||
$out .= "<option value='count' "; if ($rule_type == "count") $out .= "selected"; $out .= ">" . t("Number of times") . ":</option>\n";
|
||||
$out .= "</select>";
|
||||
|
||||
$out .= "<input name='rec_until_date' value='" . $localization->dateformat_datepicker_php($rule_until_date) . "' id='rec_until_date'>";
|
||||
$out .= "<input name='rec_until_count' value='$rule_until_count' id='rec_until_count'><br>";
|
||||
|
||||
$out .= "<label class='block'>" . t("Exceptions") . ":</label><div class='rec_exceptions'>";
|
||||
$out .= "<div class='rec_exceptions_none' ";
|
||||
if (count($recurrentce_exdates) > 0) $out .= "style='display: none;'";
|
||||
$out .= ">" . t("none") . "</div>";
|
||||
$out .= "<div class='rec_exceptions_holder' ";
|
||||
if (count($recurrentce_exdates) == 0) $out .= "style='display: none;'";
|
||||
$out .= ">";
|
||||
|
||||
foreach ($recurrentce_exdates as $exdate) {
|
||||
$out .= "<div data-timestamp='$exdate' class='except'><input type='hidden' class='rec_exception' name='rec_exceptions[]' value='$exdate'>";
|
||||
$out .= "<a href='#' class='exception_remover'>[remove]</a> ";
|
||||
$out .= $localization->date_timestamp2localDate($exdate);
|
||||
$out .= "</div>\n";
|
||||
}
|
||||
$out .= "</div><div><a href='#' class='exception_adder'>[add]</a></div>";
|
||||
$out .= "</div>\n";
|
||||
$out .= "<br>\n";
|
||||
|
||||
$out .= "</div><br>";
|
||||
|
||||
$out .= "<h2>" .t("Notification") . "</h2>";
|
||||
|
||||
/*
|
||||
$out .= '<input type="checkbox" name="notification" id="notification" ';
|
||||
if ($notification) $out .= "checked";
|
||||
$out .= '> ';
|
||||
$out .= '<span id="notification_detail" style="display: none;">
|
||||
<input name="notification_value" value="' . $notification_value . '" size="3">
|
||||
<select name="notification_type" size="1">
|
||||
<option value="minute" ';
|
||||
if ($notification_type == "minute") $out .= "selected";
|
||||
$out .= '> ' . t('Minutes') . '</option>
|
||||
<option value="hour" ';
|
||||
if ($notification_type == "hour") $out .= "selected";
|
||||
$out .= '> ' . t('Hours') . '</option>
|
||||
<option value="day" ';
|
||||
if ($notification_type == "day") echo "selected";
|
||||
$out .= '> ' . t('Days') . '</option>
|
||||
</select> ' . t('before') . '
|
||||
</span><br><br>';
|
||||
*/
|
||||
|
||||
$out .= "<script>\$(function() {
|
||||
wdcal_edit_init('" . $localization->dateformat_datepicker_js() . "', '${baseurl}/dav/');
|
||||
});</script>";
|
||||
|
||||
$out .= "<input type='submit' name='save' value='Save'></form>";
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_VObject_Component_VEvent $component
|
||||
* @param wdcal_local $localization
|
||||
*/
|
||||
function wdcal_set_component_date(&$component, &$localization) {
|
||||
if (isset($_REQUEST["allday"])) {
|
||||
$ts_start = $localization->date_local2timestamp($_REQUEST["start_date"] . " 00:00");
|
||||
$ts_end = $localization->date_local2timestamp($_REQUEST["end_date"] . " 00:00");
|
||||
$type = Sabre_VObject_Property_DateTime::DATE;
|
||||
} else {
|
||||
$ts_start = $localization->date_local2timestamp($_REQUEST["start_date"] . " " . $_REQUEST["start_time"]);
|
||||
$ts_end = $localization->date_local2timestamp($_REQUEST["end_date"] . " " . $_REQUEST["end_time"]);
|
||||
$type = Sabre_VObject_Property_DateTime::LOCALTZ;
|
||||
}
|
||||
$datetime_start = new Sabre_VObject_Property_DateTime("DTSTART");
|
||||
$datetime_start->setDateTime(new DateTime(date("Y-m-d H:i:s", $ts_start)), $type);
|
||||
$datetime_end = new Sabre_VObject_Property_DateTime("DTEND");
|
||||
$datetime_end->setDateTime(new DateTime(date("Y-m-d H:i:s", $ts_end)), $type);
|
||||
|
||||
$component->__unset("DTSTART");
|
||||
$component->__unset("DTEND");
|
||||
$component->add($datetime_start);
|
||||
$component->add($datetime_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Sabre_VObject_Component_VEvent $component
|
||||
* @param wdcal_local $localization
|
||||
*/
|
||||
function wdcal_set_component_recurrence(&$component, &$localization) {
|
||||
$component->__unset("RRULE");
|
||||
$component->__unset("EXRULE");
|
||||
$component->__unset("EXDATE");
|
||||
$component->__unset("RDATE");
|
||||
|
||||
$part_until = "";
|
||||
switch ($_REQUEST["rec_until_type"]) {
|
||||
case "date":
|
||||
$date = $localization->date_local2timestamp($_REQUEST["rec_until_date"]);
|
||||
$part_until = ";UNTIL=" . date("Ymd", $date);
|
||||
$datetime_until = new Sabre_VObject_Property_DateTime("UNTIL");
|
||||
$datetime_until->setDateTime(new DateTime(date("Y-m-d H:i:s", $date)), Sabre_VObject_Property_DateTime::DATE);
|
||||
break;
|
||||
case "count":
|
||||
$part_until = ";COUNT=" . IntVal($_REQUEST["rec_until_count"]);
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($_REQUEST["rec_frequency"]) {
|
||||
case "daily":
|
||||
$part_freq = "FREQ=DAILY";
|
||||
if (isset($_REQUEST["rec_daily_byday"])) {
|
||||
$days = array();
|
||||
foreach ($_REQUEST["rec_daily_byday"] as $x) if (in_array($x, array("MO", "TU", "WE", "TH", "FR", "SA", "SU"))) $days[] = $x;
|
||||
if (count($days) > 0) $part_freq .= ";BYDAY=" . implode(",", $days);
|
||||
}
|
||||
break;
|
||||
case "weekly":
|
||||
$part_freq = "FREQ=WEEKLY";
|
||||
if (isset($_REQUEST["rec_weekly_wkst"]) && in_array($_REQUEST["rec_weekly_wkst"], array("MO", "SU"))) $part_freq .= ";WKST=" . $_REQUEST["rec_weekly_wkst"];
|
||||
if (isset($_REQUEST["rec_weekly_byday"])) {
|
||||
$days = array();
|
||||
foreach ($_REQUEST["rec_weekly_byday"] as $x) if (in_array($x, array("MO", "TU", "WE", "TH", "FR", "SA", "SU"))) $days[] = $x;
|
||||
if (count($days) > 0) $part_freq .= ";BYDAY=" . implode(",", $days);
|
||||
}
|
||||
break;
|
||||
case "monthly":
|
||||
$part_freq = "FREQ=MONTHLY";
|
||||
break;
|
||||
case "FREQ=yearly":
|
||||
$part_freq = "FREQ=YEARLY";
|
||||
break;
|
||||
default:
|
||||
$part_freq = "";
|
||||
}
|
||||
|
||||
if ($part_freq == "") return;
|
||||
|
||||
if (isset($_REQUEST["rec_interval"])) $part_freq .= ";INTERVAL=" . InTVal($_REQUEST["rec_interval"]);
|
||||
|
||||
if (isset($_REQUEST["rec_exceptions"])) {
|
||||
$arr = array();
|
||||
foreach ($_REQUEST["rec_exceptions"] as $except) {
|
||||
$arr[] = new DateTime(date("Y-m-d H:i:s", $except));
|
||||
}
|
||||
/** @var Sabre_VObject_Property_MultiDateTime $prop */
|
||||
$prop = Sabre_VObject_Property::create("EXDATE");
|
||||
$prop->setDateTimes($arr);
|
||||
$component->add($prop);
|
||||
}
|
||||
|
||||
$rrule = $part_freq . $part_until;
|
||||
$component->add(new Sabre_VObject_Property("RRULE", $rrule));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param string $recurr_uri
|
||||
* @param int $uid
|
||||
* @param string $timezone
|
||||
* @param string $goaway_url
|
||||
* @return array
|
||||
*/
|
||||
function wdcal_postEditPage($uri, $recurr_uri = "", $uid = 0, $timezone = "", $goaway_url = "")
|
||||
{
|
||||
$uid = IntVal($uid);
|
||||
$localization = wdcal_local::getInstanceByUser($uid);
|
||||
|
||||
$server = dav_create_server(true, true, false);
|
||||
|
||||
if ($uri > 0) {
|
||||
$calendar = dav_get_current_user_calendar_by_id($server, $_REQUEST["calendar"], DAV_ACL_READ);
|
||||
$obj_uri = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($uri);
|
||||
$obj_uri = $obj_uri["uri"];
|
||||
|
||||
$vObject = dav_get_current_user_calendarobject($server, $calendar, $obj_uri, DAV_ACL_WRITE);
|
||||
$component = dav_get_eventComponent($vObject);
|
||||
|
||||
if ($component == null) return array("ok" => false, "msg" => t('Could not open component for editing'));
|
||||
} else {
|
||||
$calendar = dav_get_current_user_calendar_by_id($server, $_REQUEST["calendar"], DAV_ACL_WRITE);
|
||||
$vObject = dav_create_empty_vevent();
|
||||
$component = dav_get_eventComponent($vObject);
|
||||
$obj_uri = $component->__get("UID");
|
||||
}
|
||||
|
||||
wdcal_set_component_date($component, $localization);
|
||||
wdcal_set_component_recurrence($component, $localization);
|
||||
|
||||
$component->__unset("LOCATION");
|
||||
$component->__unset("SUMMARY");
|
||||
$component->__unset("DESCRIPTION");
|
||||
$component->__unset("X-ANIMEXXCOLOR");
|
||||
$component->add("SUMMARY", icalendar_sanitize_string(dav_compat_parse_text_serverside("summary")));
|
||||
$component->add("LOCATION", icalendar_sanitize_string(dav_compat_parse_text_serverside("location")));
|
||||
$component->add("DESCRIPTION", icalendar_sanitize_string(dav_compat_parse_text_serverside("wdcal_desc")));
|
||||
$component->add("X-ANIMEXX-COLOR", $_REQUEST["color"]);
|
||||
|
||||
$data = $vObject->serialize();
|
||||
|
||||
if ($uri == 0) {
|
||||
$calendar->createFile($obj_uri . ".ics", $data);
|
||||
} else {
|
||||
$obj = $calendar->getChild($obj_uri);
|
||||
$obj->put($data);
|
||||
}
|
||||
return array("ok" => false, "msg" => t("Saved"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_getEditPage_exception_selector() {
|
||||
header("Content-type: application/json");
|
||||
|
||||
$a = get_app();
|
||||
$localization = wdcal_local::getInstanceByUser($a->user["uid"]);
|
||||
|
||||
$vObject = wdcal_create_empty_vevent();
|
||||
|
||||
foreach($vObject->getComponents() as $component) {
|
||||
if ($component->name!=='VTIMEZONE') break;
|
||||
}
|
||||
/** @var Sabre_VObject_Component_VEvent $component */
|
||||
wdcal_set_component_date($component, $localization);
|
||||
wdcal_set_component_recurrence($component, $localization);
|
||||
|
||||
|
||||
$it = new Sabre_VObject_RecurrenceIterator($vObject, (string)$component->__get("UID"));
|
||||
$max_ts = mktime(0, 0, 0, 1, 1, CALDAV_MAX_YEAR + 1);
|
||||
$last_start = 0;
|
||||
|
||||
$o = "<ul>";
|
||||
|
||||
$i = 0;
|
||||
while($it->valid() && $last_start < $max_ts && $i++ < 1000) {
|
||||
$last_start = $it->getDtStart()->getTimestamp();
|
||||
$o .= "<li><a href='#' class='exception_selector_link' data-timestamp='$last_start'>" . $localization->date_timestamp2localDate($last_start) . "</a></li>\n";
|
||||
$it->next();
|
||||
}
|
||||
$o .= "</ul>\n";
|
||||
|
||||
return $o;
|
||||
}
|
|
@ -1,10 +1,80 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* @param int $from_version
|
||||
* @return array|string[]
|
||||
*/
|
||||
function dav_get_update_statements($from_version)
|
||||
{
|
||||
$stms = array();
|
||||
|
||||
if ($from_version <= 0) {
|
||||
$stms[] = "ALTER TABLE `dav_calendars` ADD `uri` VARCHAR( 50 ) NULL DEFAULT NULL AFTER `description` , ADD `has_vevent` TINYINT NOT NULL DEFAULT '1' AFTER `uri` , ADD `has_vtodo` TINYINT NOT NULL DEFAULT '1' AFTER `has_vevent`";
|
||||
|
||||
$stms[] = "UPDATE `dav_calendars` SET `uri` = 'private' WHERE `namespace` = 1";
|
||||
$stms[] = "UPDATE `dav_calendars` SET `uri` = 'friendica-mine' WHERE `namespace` = 2 AND `namespace_id` = 1";
|
||||
$stms[] = "UPDATE `dav_calendars` SET `uri` = 'friendica-contacts' WHERE `namespace` = 2 AND `namespace_id` = 2";
|
||||
$stms[] = "ALTER TABLE `dav_calendars` DROP PRIMARY KEY ";
|
||||
$stms[] = "ALTER TABLE `dav_calendars` ADD `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST ";
|
||||
|
||||
$stms[] = "ALTER TABLE `dav_calendarobjects` ADD `calendar_id` INT NOT NULL AFTER `id` ";
|
||||
$stms[] = "UPDATE `dav_calendarobjects` a JOIN `dav_calendars` b ON a.`namespace` = b.`namespace` AND a.`namespace_id` = b.`namespace_id` SET a.`calendar_id` = b.`id`";
|
||||
$stms[] = "ALTER TABLE `dav_calendarobjects` DROP `namespace` , DROP `namespace_id` ;";
|
||||
$stms[] = "ALTER TABLE `dav_calendarobjects` ADD INDEX ( `calendar_id` ) ";
|
||||
$stms[] = "ALTER TABLE `dav_calendarobjects` ADD `componentType` ENUM( 'VEVENT', 'VTODO' ) NOT NULL DEFAULT 'VEVENT' AFTER `calendardata` ,
|
||||
ADD `firstOccurence` TIMESTAMP NOT NULL AFTER `lastmodified` ,
|
||||
ADD `lastOccurence` TIMESTAMP NOT NULL AFTER `firstOccurence`";
|
||||
|
||||
$stms[] = "DROP TABLE `dav_jqcalendar`";
|
||||
$stms[] = "CREATE TABLE IF NOT EXISTS `dav_jqcalendar` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`ical_recurr_uri` varchar(100) DEFAULT NULL,
|
||||
`calendar_id` int(10) unsigned NOT NULL,
|
||||
`calendarobject_id` int(10) unsigned NOT NULL,
|
||||
`Subject` varchar(1000) NOT NULL,
|
||||
`StartTime` timestamp NULL DEFAULT NULL,
|
||||
`EndTime` timestamp NULL DEFAULT NULL,
|
||||
`IsEditable` tinyint(3) unsigned NOT NULL,
|
||||
`IsAllDayEvent` tinyint(4) NOT NULL,
|
||||
`IsRecurring` tinyint(4) NOT NULL,
|
||||
`Color` CHAR(6) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `calendarByStart` (`calendar_id`,`StartTime`),
|
||||
KEY `calendarobject_id` (`calendarobject_id`,`ical_recurr_uri`)
|
||||
) DEFAULT CHARSET=utf8 ";
|
||||
|
||||
|
||||
$stms[] = "ALTER TABLE `dav_notifications` ADD `calendar_id` INT NOT NULL AFTER `ical_recurr_uri` ";
|
||||
$stms[] = "ALTER TABLE `dav_notifications` DROP INDEX `ical_uri` , ADD INDEX `ical_uri` ( `calendar_id` , `ical_uri` , `ical_recurr_uri` ) ";
|
||||
$stms[] = "TRUNCATE TABLE `dav_notifications`";
|
||||
$stms[] = "ALTER TABLE `dav_notifications` DROP `namespace` , DROP `namespace_id`";
|
||||
|
||||
$stms[] = "TRUNCATE TABLE `dav_cal_virtual_object_cache`";
|
||||
$stme[] = "ALTER TABLE `dav_cal_virtual_object_cache` ADD `calendar_id` INT UNSIGNED NOT NULL AFTER `id` ";
|
||||
$stms[] = "ALTER TABLE `dav_cal_virtual_object_cache` DROP INDEX `ref_type` , ADD INDEX `ref_type` ( `calendar_id` , `data_end` ) ";
|
||||
$stms[] = "ALTER TABLE `dav_cal_virtual_object_cache` DROP `uid`, DROP `namespace` , DROP `namespace_id` ";
|
||||
|
||||
$stms[] = "CREATE TABLE `friendica`.`dav_cal_virtual_object_sync` (
|
||||
`calendar_id` INT UNSIGNED NOT NULL ,
|
||||
`date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
|
||||
PRIMARY KEY ( `calendar_id` )
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8";
|
||||
|
||||
$stms[] = "DROP TABLE `dav_cache_synchronized` ";
|
||||
|
||||
$stms[] = "UPDATE `dav_calendars` SET `namespace` = 1, `namespace_id` = `uid`"; // last
|
||||
$stms[] = "ALTER TABLE `dav_calendars` DROP `uid`";
|
||||
}
|
||||
|
||||
return $stms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function dav_get_create_statements() {
|
||||
function dav_get_create_statements()
|
||||
{
|
||||
$arr = array();
|
||||
|
||||
$arr[] = "CREATE TABLE IF NOT EXISTS `dav_addressbooks_community` (
|
||||
|
@ -69,6 +139,9 @@ function dav_get_create_statements() {
|
|||
`displayname` varchar(200) NOT NULL,
|
||||
`timezone` text NOT NULL,
|
||||
`description` varchar(500) NOT NULL,
|
||||
`uri` varchar(50) DEFAULT NULL,
|
||||
`has_vevent` tinyint(4) NOT NULL DEFAULT '1',
|
||||
`has_vtodo` tinyint(4) NOT NULL DEFAULT '1',
|
||||
`ctag` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`namespace`,`namespace_id`),
|
||||
KEY `uid` (`uid`)
|
||||
|
@ -171,10 +244,11 @@ function dav_get_create_statements() {
|
|||
/**
|
||||
* @return int
|
||||
*/
|
||||
function dav_check_tables() {
|
||||
function dav_check_tables()
|
||||
{
|
||||
$dbv = get_config("dav", "db_version");
|
||||
if ($dbv == CALDAV_DB_VERSION) return 0; // Correct
|
||||
if (is_numeric($dbv)) return 1; // Older version (update needed)
|
||||
if (is_numeric($dbv) || $dbv == "CALDAV_DB_VERSION") return 1; // Older version (update needed)
|
||||
return -1; // Not installed
|
||||
}
|
||||
|
||||
|
@ -197,3 +271,25 @@ function dav_create_tables()
|
|||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function dav_upgrade_tables()
|
||||
{
|
||||
$dbv = get_config("dav", "db_version");
|
||||
if ($dbv == "CALDAV_DB_VERSION") $ver = 0;
|
||||
else $ver = IntVal($dbv);
|
||||
$stms = dav_get_update_statements($ver);
|
||||
$errors = array();
|
||||
|
||||
global $db;
|
||||
foreach ($stms as $st) {
|
||||
$db->q($st);
|
||||
if ($db->error) $errors[] = $db->error;
|
||||
}
|
||||
|
||||
if (count($errors) == 0) set_config("dav", "db_version", CALDAV_DB_VERSION);
|
||||
|
||||
return $errors;
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* Name: Calendar with CalDAV Support
|
||||
* Description: A web-based calendar system with CalDAV-support. Also brings your Friendica-Contacts to your CardDAV-capable mobile phone. Requires PHP >= 5.3.
|
||||
* Version: 0.1.1
|
||||
* Version: 0.2.0
|
||||
* Author: Tobias Hößl <https://github.com/CatoTH/>
|
||||
*/
|
||||
|
||||
|
|
245
dav/dav_caldav_backend_virtual_friendica.inc.php
Normal file
245
dav/dav_caldav_backend_virtual_friendica.inc.php
Normal file
|
@ -0,0 +1,245 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Backend_Friendica extends Sabre_CalDAV_Backend_Virtual
|
||||
{
|
||||
|
||||
/**
|
||||
* @var null|Sabre_CalDAV_Backend_Friendica
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return Sabre_CalDAV_Backend_Friendica
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (self::$instance == null) {
|
||||
self::$instance = new Sabre_CalDAV_Backend_Friendica();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return CALDAV_NAMESPACE_PRIVATE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $calendarId
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return void
|
||||
*/
|
||||
protected static function createCache_internal($calendarId)
|
||||
{
|
||||
$calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendarId);
|
||||
|
||||
switch ($calendar["uri"]) {
|
||||
case CALDAV_FRIENDICA_MINE:
|
||||
$sql_where = " AND cid = 0";
|
||||
break;
|
||||
case CALDAV_FRIENDICA_CONTACTS:
|
||||
$sql_where = " AND cid > 0";
|
||||
break;
|
||||
default:
|
||||
throw new Sabre_DAV_Exception_NotFound();
|
||||
}
|
||||
|
||||
$r = q("SELECT * FROM `event` WHERE `uid` = %d " . $sql_where . " ORDER BY `start`", IntVal($calendar["namespace_id"]));
|
||||
|
||||
foreach ($r as $row) {
|
||||
$uid = $calendar["uri"] . "-" . $row["id"];
|
||||
$vevent = dav_create_empty_vevent($uid);
|
||||
$component = dav_get_eventComponent($vevent);
|
||||
|
||||
if ($row["adjust"]) {
|
||||
$start = datetime_convert('UTC', date_default_timezone_get(), $row["start"]);
|
||||
$finish = datetime_convert('UTC', date_default_timezone_get(), $row["finish"]);
|
||||
} else {
|
||||
$start = $row["start"];
|
||||
$finish = $row["finish"];
|
||||
}
|
||||
|
||||
$summary = ($row["summary"] != "" ? $row["summary"] : $row["desc"]);
|
||||
$desc = ($row["summary"] != "" ? $row["desc"] : "");
|
||||
$component->add("SUMMARY", icalendar_sanitize_string($summary));
|
||||
$component->add("LOCATION", icalendar_sanitize_string($row["location"]));
|
||||
$component->add("DESCRIPTION", icalendar_sanitize_string($desc));
|
||||
|
||||
$ts_start = wdcal_mySql2PhpTime($start);
|
||||
$ts_end = wdcal_mySql2PhpTime($start);
|
||||
|
||||
$allday = (strpos($start, "00:00:00") !== false && strpos($finish, "00:00:00") !== false);
|
||||
$type = ($allday ? Sabre_VObject_Property_DateTime::DATE : Sabre_VObject_Property_DateTime::LOCALTZ);
|
||||
|
||||
$datetime_start = new Sabre_VObject_Property_DateTime("DTSTART");
|
||||
$datetime_start->setDateTime(new DateTime(date("Y-m-d H:i:s", $ts_start)), $type);
|
||||
$datetime_end = new Sabre_VObject_Property_DateTime("DTEND");
|
||||
$datetime_end->setDateTime(new DateTime(date("Y-m-d H:i:s", $ts_end)), $type);
|
||||
|
||||
$component->add($datetime_start);
|
||||
$component->add($datetime_end);
|
||||
|
||||
$data = $vevent->serialize();
|
||||
|
||||
q("INSERT INTO %s%scal_virtual_object_cache (`calendar_id`, `data_uri`, `data_summary`, `data_location`, `data_start`, `data_end`, `data_allday`, `data_type`,
|
||||
`calendardata`, `size`, `etag`) VALUES (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', %d, '%s')",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId, dbesc($uid), dbesc($summary), dbesc($row["location"]), dbesc($row["start"]), dbesc($row["finish"]),
|
||||
($allday ? 1 : 0), dbesc(($row["type"] == "birthday" ? "birthday" : "")), dbesc($data), strlen($data), md5($data));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $row
|
||||
* @param array $calendar
|
||||
* @param string $base_path
|
||||
* @return array
|
||||
*/
|
||||
private function jqcal2wdcal($row, $calendar, $base_path)
|
||||
{
|
||||
if ($row["adjust"]) {
|
||||
$start = datetime_convert('UTC', date_default_timezone_get(), $row["start"]);
|
||||
$finish = datetime_convert('UTC', date_default_timezone_get(), $row["finish"]);
|
||||
} else {
|
||||
$start = $row["start"];
|
||||
$finish = $row["finish"];
|
||||
}
|
||||
|
||||
$allday = (strpos($start, "00:00:00") !== false && strpos($finish, "00:00:00") !== false);
|
||||
|
||||
$summary = (($row["summary"]) ? $row["summary"] : substr(preg_replace("/\[[^\]]*\]/", "", $row["desc"]), 0, 100));
|
||||
|
||||
return array(
|
||||
"jq_id" => $row["id"],
|
||||
"ev_id" => $row["id"],
|
||||
"summary" => escape_tags($summary),
|
||||
"start" => wdcal_mySql2PhpTime($start),
|
||||
"end" => wdcal_mySql2PhpTime($finish),
|
||||
"is_allday" => ($allday ? 1 : 0),
|
||||
"is_moredays" => (substr($start, 0, 10) != substr($finish, 0, 10)),
|
||||
"is_recurring" => ($row["type"] == "birthday"),
|
||||
"color" => "#f8f8ff",
|
||||
"is_editable" => 0,
|
||||
"is_editable_quick" => 0,
|
||||
"location" => $row["location"],
|
||||
"attendees" => '',
|
||||
"has_notification" => 0,
|
||||
"url_detail" => $base_path . "/events/event/" . $row["id"],
|
||||
"url_edit" => "",
|
||||
"special_type" => ($row["type"] == "birthday" ? "birthday" : ""),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $calendarId
|
||||
* @param string $date_from
|
||||
* @param string $date_to
|
||||
* @param string $base_path
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return array
|
||||
*/
|
||||
public function listItemsByRange($calendarId, $date_from, $date_to, $base_path)
|
||||
{
|
||||
$calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendarId);
|
||||
|
||||
if ($calendar["namespace"] != CALDAV_NAMESPACE_PRIVATE) throw new Sabre_DAV_Exception_NotFound();
|
||||
|
||||
switch ($calendar["uri"]) {
|
||||
case CALDAV_FRIENDICA_MINE:
|
||||
$sql_where = " AND cid = 0";
|
||||
break;
|
||||
case CALDAV_FRIENDICA_CONTACTS:
|
||||
$sql_where = " AND cid > 0";
|
||||
break;
|
||||
default:
|
||||
throw new Sabre_DAV_Exception_NotFound();
|
||||
}
|
||||
|
||||
if ($date_from != "") {
|
||||
if (is_numeric($date_from)) $sql_where .= " AND `finish` >= '" . date("Y-m-d H:i:s", $date_from) . "'";
|
||||
else $sql_where .= " AND `finish` >= '" . dbesc($date_from) . "'";
|
||||
}
|
||||
if ($date_to != "") {
|
||||
if (is_numeric($date_to)) $sql_where .= " AND `start` <= '" . date("Y-m-d H:i:s", $date_to) . "'";
|
||||
else $sql_where .= " AND `start` <= '" . dbesc($date_to) . "'";
|
||||
}
|
||||
$ret = array();
|
||||
|
||||
$r = q("SELECT * FROM `event` WHERE `uid` = %d " . $sql_where . " ORDER BY `start`", IntVal($calendar["namespace_id"]));
|
||||
|
||||
$a = get_app();
|
||||
foreach ($r as $row) {
|
||||
$r = $this->jqcal2wdcal($row, $calendar, $a->get_baseurl());
|
||||
$r["calendar_id"] = $calendar["id"];
|
||||
$ret[] = $r;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri)
|
||||
{
|
||||
$n = dav_compat_principal2namespace($principalUri);
|
||||
if ($n["namespace"] != $this->getNamespace()) return array();
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $this->getNamespace(), IntVal($n["namespace_id"]));
|
||||
$ret = array();
|
||||
foreach ($cals as $cal) {
|
||||
if (!in_array($cal["uri"], $GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"])) continue;
|
||||
|
||||
$dat = array(
|
||||
"id" => $cal["id"],
|
||||
"uri" => $cal["uri"],
|
||||
"principaluri" => $principalUri,
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}getctag' => $cal['ctag'] ? $cal['ctag'] : '0',
|
||||
"calendar_class" => "Sabre_CalDAV_Calendar_Virtual",
|
||||
);
|
||||
foreach ($this->propertyMap as $key=> $field) $dat[$key] = $cal[$field];
|
||||
|
||||
$ret[] = $dat;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $calendar_id
|
||||
* @param int $calendarobject_id
|
||||
* @return string
|
||||
*/
|
||||
function getItemDetailRedirect($calendar_id, $calendarobject_id)
|
||||
{
|
||||
$a = get_app();
|
||||
$item = q("SELECT `id` FROM `item` WHERE `event-id` = %d AND `uid` = %d AND deleted = 0", IntVal($calendarobject_id), $a->user["uid"]);
|
||||
if (count($item) == 0) return "/events/";
|
||||
return "/display/" . $a->user["nickname"] . "/" . IntVal($item[0]["id"]);
|
||||
|
||||
}
|
||||
}
|
336
dav/dav_carddav_backend_virtual_friendica.inc.php
Normal file
336
dav/dav_carddav_backend_virtual_friendica.inc.php
Normal file
|
@ -0,0 +1,336 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CardDAV_Backend_FriendicaCommunity extends Sabre_CardDAV_Backend_Abstract
|
||||
{
|
||||
|
||||
/**
|
||||
* @var null|Sabre_CardDAV_Backend_FriendicaCommunity
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return Sabre_CardDAV_Backend_FriendicaCommunity
|
||||
*/
|
||||
public static function getInstance() {
|
||||
if (self::$instance == null) {
|
||||
self::$instance = new Sabre_CardDAV_Backend_FriendicaCommunity();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the object
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of addressbooks for a specific user.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getAddressBooksForUser($principalUri)
|
||||
{
|
||||
$uid = dav_compat_principal2uid($principalUri);
|
||||
|
||||
$addressBooks = array();
|
||||
|
||||
$books = q("SELECT ctag FROM %s%saddressbooks_community WHERE uid = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($uid));
|
||||
if (count($books) == 0) {
|
||||
q("INSERT INTO %s%saddressbooks_community (uid, ctag) VALUES (%d, 1)", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($uid));
|
||||
$ctag = 1;
|
||||
} else {
|
||||
$ctag = $books[0]["ctag"];
|
||||
}
|
||||
$addressBooks[] = array(
|
||||
'id' => CARDDAV_NAMESPACE_COMMUNITYCONTACTS . "-" . $uid,
|
||||
'uri' => "friendica",
|
||||
'principaluri' => $principalUri,
|
||||
'{DAV:}displayname' => t("Friendica-Contacts"),
|
||||
'{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' => t("Your Friendica-Contacts"),
|
||||
'{http://calendarserver.org/ns/}getctag' => $ctag,
|
||||
'{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}supported-address-data' =>
|
||||
new Sabre_CardDAV_Property_SupportedAddressData(),
|
||||
);
|
||||
|
||||
return $addressBooks;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates an addressbook's properties
|
||||
*
|
||||
* See Sabre_DAV_IProperties for a description of the mutations array, as
|
||||
* well as the return value.
|
||||
*
|
||||
* @param string $addressBookId
|
||||
* @param array $mutations
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @see Sabre_DAV_IProperties::updateProperties
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateAddressBook($addressBookId, array $mutations)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new address book
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $url Just the 'basename' of the url.
|
||||
* @param array $properties
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function createAddressBook($principalUri, $url, array $properties)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entire addressbook and all its contents
|
||||
*
|
||||
* @param int $addressBookId
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function deleteAddressBook($addressBookId)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $contact
|
||||
* @return array
|
||||
*/
|
||||
private function dav_contactarr2vcardsource($contact)
|
||||
{
|
||||
$name = explode(" ", $contact["name"]);
|
||||
$first_name = $last_name = "";
|
||||
$middle_name = array();
|
||||
$num = count($name);
|
||||
for ($i = 0; $i < $num && $first_name == ""; $i++) if ($name[$i] != "") {
|
||||
$first_name = $name[$i];
|
||||
unset($name[$i]);
|
||||
}
|
||||
for ($i = $num - 1; $i >= 0 && $last_name == ""; $i--) if (isset($name[$i]) && $name[$i] != "") {
|
||||
$last_name = $name[$i];
|
||||
unset($name[$i]);
|
||||
}
|
||||
foreach ($name as $n) if ($n != "") $middle_name[] = $n;
|
||||
$vcarddata = new vcard_source_data($first_name, implode(" ", $middle_name), $last_name);
|
||||
$vcarddata->homepages[] = new vcard_source_data_homepage("pref", $contact["url"]);
|
||||
$vcarddata->last_update = ($contact["last-update"] > 0 ? $contact["last-update"] : $contact["created"]);
|
||||
|
||||
$photo = q("SELECT * FROM photo WHERE `contact-id` = %d ORDER BY scale DESC", $contact["id"]); //prefer size 80x80
|
||||
if ($photo && count($photo) > 0) {
|
||||
$photodata = new vcard_source_data_photo();
|
||||
$photodata->width = $photo[0]["width"];
|
||||
$photodata->height = $photo[0]["height"];
|
||||
$photodata->type = "JPEG";
|
||||
$photodata->binarydata = $photo[0]["data"];
|
||||
$vcarddata->photo = $photodata;
|
||||
}
|
||||
|
||||
switch ($contact["network"]) {
|
||||
case "face":
|
||||
$vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("facebook", $contact["notify"], "http://www.facebook.com/" . $contact["notify"]);
|
||||
break;
|
||||
case "dfrn":
|
||||
$vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("dfrn", $contact["nick"], $contact["url"]);
|
||||
break;
|
||||
case "twitter":
|
||||
$vcarddata->socialnetworks[] = new vcard_source_data_socialnetwork("twitter", $contact["nick"], "http://twitter.com/" . $contact["nick"]); // @TODO Stimmt das?
|
||||
break;
|
||||
}
|
||||
|
||||
$vcard = vcard_source_compile($vcarddata);
|
||||
return array(
|
||||
"id" => $contact["id"],
|
||||
"carddata" => $vcard,
|
||||
"uri" => $contact["id"] . ".vcf",
|
||||
"lastmodified" => wdcal_mySql2PhpTime($vcarddata->last_update),
|
||||
"etag" => md5($vcard),
|
||||
"size" => strlen($vcard),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uid
|
||||
* @param array|int[] $exclude_ids
|
||||
* @return array
|
||||
*/
|
||||
private function dav_getCommunityContactsVCards($uid = 0, $exclude_ids = array())
|
||||
{
|
||||
$notin = (count($exclude_ids) > 0 ? " AND id NOT IN (" . implode(", ", $exclude_ids) . ") " : "");
|
||||
$uid = IntVal($uid);
|
||||
$contacts = q("SELECT * FROM `contact` WHERE `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `hidden` = 0 AND `archive` = 0 $notin ORDER BY `name` ASC", $uid);
|
||||
|
||||
$retdata = array();
|
||||
foreach ($contacts as $contact) {
|
||||
$x = $this->dav_contactarr2vcardsource($contact);
|
||||
$x["contact"] = $contact["id"];
|
||||
$retdata[] = $x;
|
||||
}
|
||||
return $retdata;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all cards for a specific addressbook id.
|
||||
*
|
||||
* This method should return the following properties for each card:
|
||||
* * carddata - raw vcard data
|
||||
* * uri - Some unique url
|
||||
* * lastmodified - A unix timestamp
|
||||
*
|
||||
* It's recommended to also return the following properties:
|
||||
* * etag - A unique etag. This must change every time the card changes.
|
||||
* * size - The size of the card in bytes.
|
||||
*
|
||||
* If these last two properties are provided, less time will be spent
|
||||
* calculating them. If they are specified, you can also ommit carddata.
|
||||
* This may speed up certain requests, especially with large cards.
|
||||
*
|
||||
* @param string $addressbookId
|
||||
* @return array
|
||||
*/
|
||||
public function getCards($addressbookId)
|
||||
{
|
||||
$add = explode("-", $addressbookId);
|
||||
|
||||
$indb = q('SELECT id, carddata, uri, lastmodified, etag, size, contact, manually_deleted FROM %s%scards WHERE namespace = %d AND namespace_id = %d',
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($add[0]), IntVal($add[1])
|
||||
);
|
||||
$found_contacts = array();
|
||||
$contacts = array();
|
||||
foreach ($indb as $x) {
|
||||
if ($x["manually_deleted"] == 0) $contacts[] = $x;
|
||||
$found_contacts[] = IntVal($x["contact"]);
|
||||
}
|
||||
$new_found = $this->dav_getCommunityContactsVCards($add[1], $found_contacts);
|
||||
foreach ($new_found as $new) {
|
||||
q("INSERT INTO %s%scards (namespace, namespace_id, contact, carddata, uri, lastmodified, manually_edited, manually_deleted, etag, size)
|
||||
VALUES (%d, %d, %d, '%s', '%s', %d, 0, 0, '%s', %d)", CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
|
||||
IntVal($add[0]), IntVal($add[1]), IntVal($new["contact"]), dbesc($new["carddata"]), dbesc($new["uri"]), time(), md5($new["carddata"]), strlen($new["carddata"])
|
||||
);
|
||||
}
|
||||
return array_merge($contacts, $new_found);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specfic card.
|
||||
*
|
||||
* The same set of properties must be returned as with getCards. The only
|
||||
* exception is that 'carddata' is absolutely required.
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return array
|
||||
*/
|
||||
public function getCard($addressBookId, $cardUri)
|
||||
{
|
||||
$x = explode("-", $addressBookId);
|
||||
$x = q("SELECT id, carddata, uri, lastmodified, etag, size FROM %s%scards WHERE namespace = %d AND namespace_id = %d AND uri = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]), dbesc($cardUri));
|
||||
if (count($x) == 0) throw new Sabre_DAV_Exception_NotFound();
|
||||
return $x[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new card.
|
||||
*
|
||||
* The addressbook id will be passed as the first argument. This is the
|
||||
* same id as it is returned from the getAddressbooksForUser method.
|
||||
*
|
||||
* The cardUri is a base uri, and doesn't include the full path. The
|
||||
* cardData argument is the vcard body, and is passed as a string.
|
||||
*
|
||||
* It is possible to return an ETag from this method. This ETag is for the
|
||||
* newly created resource, and must be enclosed with double quotes (that
|
||||
* is, the string itself must contain the double quotes).
|
||||
*
|
||||
* You should only return the ETag if you store the carddata as-is. If a
|
||||
* subsequent GET request on the same card does not have the same body,
|
||||
* byte-by-byte and you did return an ETag here, clients tend to get
|
||||
* confused.
|
||||
*
|
||||
* If you don't return an ETag, you can just return null.
|
||||
*
|
||||
* @param string $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string $cardData
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return string
|
||||
*/
|
||||
public function createCard($addressBookId, $cardUri, $cardData)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a card.
|
||||
*
|
||||
* The addressbook id will be passed as the first argument. This is the
|
||||
* same id as it is returned from the getAddressbooksForUser method.
|
||||
*
|
||||
* The cardUri is a base uri, and doesn't include the full path. The
|
||||
* cardData argument is the vcard body, and is passed as a string.
|
||||
*
|
||||
* It is possible to return an ETag from this method. This ETag should
|
||||
* match that of the updated resource, and must be enclosed with double
|
||||
* quotes (that is: the string itself must contain the actual quotes).
|
||||
*
|
||||
* You should only return the ETag if you store the carddata as-is. If a
|
||||
* subsequent GET request on the same card does not have the same body,
|
||||
* byte-by-byte and you did return an ETag here, clients tend to get
|
||||
* confused.
|
||||
*
|
||||
* If you don't return an ETag, you can just return null.
|
||||
*
|
||||
* @param string $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string $cardData
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateCard($addressBookId, $cardUri, $cardData)
|
||||
{
|
||||
$x = explode("-", $addressBookId);
|
||||
|
||||
$etag = md5($cardData);
|
||||
q("UPDATE %s%scards SET carddata = '%s', lastmodified = %d, etag = '%s', size = %d, manually_edited = 1 WHERE uri = '%s' AND namespace = %d AND namespace_id =%d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($cardData), time(), $etag, strlen($cardData), dbesc($cardUri), IntVal($x[10]), IntVal($x[1])
|
||||
);
|
||||
q('UPDATE %s%saddressbooks_community SET ctag = ctag + 1 WHERE uid = %d', CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[1]));
|
||||
|
||||
return '"' . $etag . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a card
|
||||
*
|
||||
* @param string $addressBookId
|
||||
* @param string $cardUri
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteCard($addressBookId, $cardUri)
|
||||
{
|
||||
$x = explode("-", $addressBookId);
|
||||
|
||||
q("UPDATE %s%scards SET manually_deleted = 1 WHERE namespace = %d AND namespace_id = %d AND uri = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]), dbesc($cardUri));
|
||||
q('UPDATE %s%saddressbooks_community SET ctag = ctag + 1 WHERE uid = %d', CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[1]));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,38 @@
|
|||
<?php
|
||||
|
||||
class Sabre_DAV_Auth_Backend_Friendica extends Sabre_DAV_Auth_Backend_AbstractBasic {
|
||||
class Sabre_DAV_Auth_Backend_Std extends Sabre_DAV_Auth_Backend_AbstractBasic {
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @var Sabre_DAV_Auth_Backend_Std|null
|
||||
*/
|
||||
private static $intstance = null;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return Sabre_DAV_Auth_Backend_Std
|
||||
*/
|
||||
public static function &getInstance() {
|
||||
if (is_null(self::$intstance)) {
|
||||
self::$intstance = new Sabre_DAV_Auth_Backend_Std();
|
||||
}
|
||||
return self::$intstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getUsers() {
|
||||
return array($this->currentUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getCurrentUser() {
|
||||
return $this->currentUser;
|
||||
}
|
||||
|
@ -27,6 +50,12 @@ class Sabre_DAV_Auth_Backend_Friendica extends Sabre_DAV_Auth_Backend_AbstractBa
|
|||
*/
|
||||
public function authenticate(Sabre_DAV_Server $server, $realm) {
|
||||
|
||||
$a = get_app();
|
||||
if (isset($a->user["uid"])) {
|
||||
$this->currentUser = strtolower($a->user["nickname"]);
|
||||
return true;
|
||||
}
|
||||
|
||||
$auth = new Sabre_HTTP_BasicAuth();
|
||||
$auth->setHTTPRequest($server->httpRequest);
|
||||
$auth->setHTTPResponse($server->httpResponse);
|
||||
|
@ -47,12 +76,18 @@ class Sabre_DAV_Auth_Backend_Friendica extends Sabre_DAV_Auth_Backend_AbstractBa
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateUserPass($username, $password) {
|
||||
|
||||
$user = array(
|
||||
'uri' => "/" . 'principals/users/' . strtolower($username),
|
||||
$encrypted = hash('whirlpool',trim($password));
|
||||
$r = q("SELECT COUNT(*) anz FROM `user` WHERE `nickname` = '%s' AND `password` = '%s' AND `blocked` = 0 AND `account_expired` = 0 AND `verified` = 1 LIMIT 1",
|
||||
dbesc(trim($username)),
|
||||
dbesc($encrypted)
|
||||
);
|
||||
return $user;
|
||||
return ($r[0]["anz"] == 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
|
||||
class Sabre_DAVACL_PrincipalBackend_Friendica implements Sabre_DAVACL_IPrincipalBackend
|
||||
class Sabre_DAVACL_PrincipalBackend_Std implements Sabre_DAVACL_IPrincipalBackend
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -24,6 +24,23 @@ class Sabre_DAVACL_PrincipalBackend_Friendica implements Sabre_DAVACL_IPrincipal
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @var Sabre_DAVACL_IPrincipalBackend|null
|
||||
*/
|
||||
private static $intstance = null;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return Sabre_DAVACL_IPrincipalBackend
|
||||
*/
|
||||
public static function &getInstance() {
|
||||
if (is_null(self::$intstance)) {
|
||||
$authBackend = Sabre_DAV_Auth_Backend_Std::getInstance();
|
||||
self::$intstance = new Sabre_DAVACL_PrincipalBackend_Std($authBackend);
|
||||
}
|
||||
return self::$intstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of principals based on a prefix.
|
||||
*
|
||||
|
|
375
dav/jqueryui/jquery-ui-1.8.21.custom.css
vendored
Normal file
375
dav/jqueryui/jquery-ui-1.8.21.custom.css
vendored
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*!
|
||||
* jQuery UI CSS Framework 1.8.21
|
||||
*
|
||||
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*/
|
||||
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden { display: none; }
|
||||
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
|
||||
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
|
||||
.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
|
||||
.ui-helper-clearfix:after { clear: both; }
|
||||
.ui-helper-clearfix { zoom: 1; }
|
||||
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
|
||||
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-disabled { cursor: default !important; }
|
||||
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI CSS Framework 1.8.21
|
||||
*
|
||||
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
|
||||
*/
|
||||
|
||||
|
||||
/* Component containers
|
||||
----------------------------------*/
|
||||
.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
|
||||
.ui-widget .ui-widget { font-size: 1em; }
|
||||
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
|
||||
.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
|
||||
.ui-widget-content a { color: #333333; }
|
||||
.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
|
||||
.ui-widget-header a { color: #ffffff; }
|
||||
|
||||
/* Interaction states
|
||||
----------------------------------*/
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }
|
||||
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
|
||||
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
|
||||
.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
|
||||
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
|
||||
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
|
||||
.ui-widget :active { outline: none; }
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }
|
||||
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
|
||||
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }
|
||||
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
|
||||
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
|
||||
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
|
||||
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
|
||||
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
|
||||
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
|
||||
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
|
||||
.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); }
|
||||
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
|
||||
.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
|
||||
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
|
||||
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); }
|
||||
|
||||
/* positioning */
|
||||
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||
.ui-icon-extlink { background-position: -32px -80px; }
|
||||
.ui-icon-newwin { background-position: -48px -80px; }
|
||||
.ui-icon-refresh { background-position: -64px -80px; }
|
||||
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||
.ui-icon-document { background-position: -32px -96px; }
|
||||
.ui-icon-document-b { background-position: -48px -96px; }
|
||||
.ui-icon-note { background-position: -64px -96px; }
|
||||
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||
.ui-icon-comment { background-position: -128px -96px; }
|
||||
.ui-icon-person { background-position: -144px -96px; }
|
||||
.ui-icon-print { background-position: -160px -96px; }
|
||||
.ui-icon-trash { background-position: -176px -96px; }
|
||||
.ui-icon-locked { background-position: -192px -96px; }
|
||||
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||
.ui-icon-tag { background-position: -240px -96px; }
|
||||
.ui-icon-home { background-position: 0 -112px; }
|
||||
.ui-icon-flag { background-position: -16px -112px; }
|
||||
.ui-icon-calendar { background-position: -32px -112px; }
|
||||
.ui-icon-cart { background-position: -48px -112px; }
|
||||
.ui-icon-pencil { background-position: -64px -112px; }
|
||||
.ui-icon-clock { background-position: -80px -112px; }
|
||||
.ui-icon-disk { background-position: -96px -112px; }
|
||||
.ui-icon-calculator { background-position: -112px -112px; }
|
||||
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||
.ui-icon-search { background-position: -160px -112px; }
|
||||
.ui-icon-wrench { background-position: -176px -112px; }
|
||||
.ui-icon-gear { background-position: -192px -112px; }
|
||||
.ui-icon-heart { background-position: -208px -112px; }
|
||||
.ui-icon-star { background-position: -224px -112px; }
|
||||
.ui-icon-link { background-position: -240px -112px; }
|
||||
.ui-icon-cancel { background-position: 0 -128px; }
|
||||
.ui-icon-plus { background-position: -16px -128px; }
|
||||
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||
.ui-icon-minus { background-position: -48px -128px; }
|
||||
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||
.ui-icon-close { background-position: -80px -128px; }
|
||||
.ui-icon-closethick { background-position: -96px -128px; }
|
||||
.ui-icon-key { background-position: -112px -128px; }
|
||||
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||
.ui-icon-scissors { background-position: -144px -128px; }
|
||||
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||
.ui-icon-copy { background-position: -176px -128px; }
|
||||
.ui-icon-contact { background-position: -192px -128px; }
|
||||
.ui-icon-image { background-position: -208px -128px; }
|
||||
.ui-icon-video { background-position: -224px -128px; }
|
||||
.ui-icon-script { background-position: -240px -128px; }
|
||||
.ui-icon-alert { background-position: 0 -144px; }
|
||||
.ui-icon-info { background-position: -16px -144px; }
|
||||
.ui-icon-notice { background-position: -32px -144px; }
|
||||
.ui-icon-help { background-position: -48px -144px; }
|
||||
.ui-icon-check { background-position: -64px -144px; }
|
||||
.ui-icon-bullet { background-position: -80px -144px; }
|
||||
.ui-icon-radio-off { background-position: -96px -144px; }
|
||||
.ui-icon-radio-on { background-position: -112px -144px; }
|
||||
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||
.ui-icon-play { background-position: 0 -160px; }
|
||||
.ui-icon-pause { background-position: -16px -160px; }
|
||||
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||
.ui-icon-stop { background-position: -96px -160px; }
|
||||
.ui-icon-eject { background-position: -112px -160px; }
|
||||
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||
.ui-icon-power { background-position: 0 -176px; }
|
||||
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||
.ui-icon-signal { background-position: -32px -176px; }
|
||||
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Corner radius */
|
||||
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
|
||||
.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*!
|
||||
* jQuery UI Dialog 1.8.21
|
||||
*
|
||||
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Dialog#theming
|
||||
*/
|
||||
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
|
||||
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
|
||||
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
|
||||
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
|
||||
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
|
||||
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
|
||||
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
|
||||
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
|
||||
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
|
||||
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
|
||||
.ui-draggable .ui-dialog-titlebar { cursor: move; }
|
||||
/*!
|
||||
* jQuery UI Datepicker 1.8.21
|
||||
*
|
||||
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Datepicker#theming
|
||||
*/
|
||||
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
|
||||
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
|
||||
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
|
||||
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
|
||||
.ui-datepicker .ui-datepicker-prev { left:2px; }
|
||||
.ui-datepicker .ui-datepicker-next { right:2px; }
|
||||
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
|
||||
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
|
||||
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
|
||||
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
|
||||
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
|
||||
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
|
||||
.ui-datepicker select.ui-datepicker-month,
|
||||
.ui-datepicker select.ui-datepicker-year { width: 49%;}
|
||||
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
|
||||
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
|
||||
.ui-datepicker td { border: 0; padding: 1px; }
|
||||
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
|
||||
|
||||
/* with multiple calendars */
|
||||
.ui-datepicker.ui-datepicker-multi { width:auto; }
|
||||
.ui-datepicker-multi .ui-datepicker-group { float:left; }
|
||||
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
|
||||
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
|
||||
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
|
||||
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
|
||||
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
|
||||
|
||||
/* RTL support */
|
||||
.ui-datepicker-rtl { direction: rtl; }
|
||||
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
||||
|
||||
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
|
||||
.ui-datepicker-cover {
|
||||
display: none; /*sorry for IE5*/
|
||||
display/**/: block; /*sorry for IE5*/
|
||||
position: absolute; /*must have*/
|
||||
z-index: -1; /*must have*/
|
||||
filter: mask(); /*must have*/
|
||||
top: -4px; /*must have*/
|
||||
left: -4px; /*must have*/
|
||||
width: 200px; /*must have*/
|
||||
height: 200px; /*must have*/
|
||||
}
|
21
dav/jqueryui/jquery-ui-1.8.21.custom.min.js
vendored
Normal file
21
dav/jqueryui/jquery-ui-1.8.21.custom.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
23
dav/jqueryui/jquery.ui.datepicker-de.js
vendored
Normal file
23
dav/jqueryui/jquery.ui.datepicker-de.js
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* German initialisation for the jQuery UI date picker plugin. */
|
||||
/* Written by Milian Wolff (mail@milianw.de). */
|
||||
jQuery(function($){
|
||||
$.datepicker.regional['de'] = {
|
||||
closeText: 'schließen',
|
||||
prevText: '<zurück',
|
||||
nextText: 'Vor>',
|
||||
currentText: 'heute',
|
||||
monthNames: ['Januar','Februar','März','April','Mai','Juni',
|
||||
'Juli','August','September','Oktober','November','Dezember'],
|
||||
monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',
|
||||
'Jul','Aug','Sep','Okt','Nov','Dez'],
|
||||
dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
|
||||
dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
|
||||
dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
|
||||
weekHeader: 'Wo',
|
||||
dateFormat: 'dd.mm.yy',
|
||||
firstDay: 1,
|
||||
isRTL: false,
|
||||
showMonthAfterYear: false,
|
||||
yearSuffix: ''};
|
||||
$.datepicker.setDefaults($.datepicker.regional['de']);
|
||||
});
|
|
@ -8,8 +8,8 @@ function wdcal_addRequiredHeaders()
|
|||
{
|
||||
$a = get_app();
|
||||
|
||||
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery-ui-1.8.20.custom.css' . '" media="all" />' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery-ui-1.8.20.custom.min.js"></script>' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery-ui-1.8.21.custom.css' . '" media="all" />' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery-ui-1.8.21.custom.min.js"></script>' . "\r\n";
|
||||
|
||||
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/dav/wdcal.css' . '" media="all" />' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/common/wdcal.js"></script>' . "\r\n";
|
||||
|
@ -20,6 +20,7 @@ function wdcal_addRequiredHeaders()
|
|||
switch (get_config("system", "language")) {
|
||||
case "de":
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/common/wdcal/js/wdCalendar_lang_DE.js"></script>' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery.ui.datepicker-de.js"></script>' . "\r\n";
|
||||
break;
|
||||
default:
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/common/wdcal/js/wdCalendar_lang_EN.js"></script>' . "\r\n";
|
||||
|
@ -34,10 +35,12 @@ function wdcal_addRequiredHeaders()
|
|||
*/
|
||||
function wdcal_addRequiredHeadersEdit()
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery-ui-1.8.20.custom.css' . '" media="all" />' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery-ui-1.8.20.custom.min.js"></script>' . "\r\n";
|
||||
$a = get_app();
|
||||
$localization = wdcal_local::getInstanceByUser($a->user["uid"]);
|
||||
|
||||
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery-ui-1.8.21.custom.css' . '" media="all" />' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery-ui-1.8.21.custom.min.js"></script>' . "\r\n";
|
||||
|
||||
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/dav/colorpicker/colorPicker.css' . '" media="all" />' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/colorpicker/jquery.colorPicker.min.js"></script>' . "\r\n";
|
||||
|
@ -48,12 +51,56 @@ function wdcal_addRequiredHeadersEdit()
|
|||
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/dav/wdcal.css' . '" media="all" />' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/common/wdcal.js"></script>' . "\r\n";
|
||||
|
||||
switch ($localization->getLanguageCode()) {
|
||||
case "de":
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/common/wdcal/js/wdCalendar_lang_DE.js"></script>' . "\r\n";
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/jqueryui/jquery.ui.datepicker-de.js"></script>' . "\r\n";
|
||||
break;
|
||||
default:
|
||||
$a->page['htmlhead'] .= '<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/dav/common/wdcal/js/wdCalendar_lang_EN.js"></script>' . "\r\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|int[] $calendars
|
||||
*/
|
||||
function wdcal_print_user_ics($calendars = array())
|
||||
{
|
||||
$add = "";
|
||||
if (count($calendars) > 0) {
|
||||
$c = array();
|
||||
foreach ($calendars as $i) $c[] = IntVal($i);
|
||||
$add = " AND `id` IN (" . implode(", ", $c) . ")";
|
||||
}
|
||||
|
||||
$a = get_app();
|
||||
header("Content-type: text/plain");
|
||||
|
||||
$str = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Friendica//DAV-Plugin//EN\r\n";
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d %s", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, $a->user["uid"], $add);
|
||||
if (count($cals) > 0) {
|
||||
$ids = array();
|
||||
foreach ($cals as $c) $ids[] = IntVal($c["id"]);
|
||||
$objs = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` IN (" . implode(", ", $ids) . ") ORDER BY `firstOccurence`", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
|
||||
foreach ($objs as $obj) {
|
||||
preg_match("/BEGIN:VEVENT(.*)END:VEVENT/siu", $obj["calendardata"], $matches);
|
||||
$str2 = preg_replace("/([^\\r])\\n/siu", "\\1\r\n", $matches[0]);
|
||||
$str2 = preg_replace("/MAILTO:.*[^:a-z0-9_\+äöüß\\n\\n@-]+.*(:|\\r\\n[^ ])/siU", "\\1", $str2);
|
||||
$str .= $str2 . "\r\n";
|
||||
}
|
||||
}
|
||||
$str .= "END:VCALENDAR\r\n";
|
||||
|
||||
echo $str;
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array|DBClass_friendica_calendars[] $calendars
|
||||
* @param array $calendar_preselected
|
||||
* @param array|Sabre_CalDAV_Calendar[] $calendars
|
||||
* @param array|int[] $calendars_selected
|
||||
* @param string $data_feed_url
|
||||
* @param string $view
|
||||
* @param int $theme
|
||||
|
@ -64,14 +111,17 @@ function wdcal_addRequiredHeadersEdit()
|
|||
* @param bool $show_nav
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_printCalendar($calendars, $calendar_preselected, $data_feed_url, $view = "week", $theme = 0, $height_diff = 175, $readonly = false, $curr_day = "", $add_params = array(), $show_nav = true)
|
||||
function wdcal_printCalendar($calendars, $calendars_selected, $data_feed_url, $view = "week", $theme = 0, $height_diff = 175, $readonly = false, $curr_day = "", $add_params = array(), $show_nav = true)
|
||||
{
|
||||
|
||||
$a = get_app();
|
||||
$localization = wdcal_local::getInstanceByUser($a->user["uid"]);
|
||||
|
||||
$cals_avail = array();
|
||||
foreach ($calendars as $c) $cals_avail[] = array("ns" => $c->namespace, "id" => $c->namespace_id, "displayname" => $c->displayname);
|
||||
if (count($calendars_selected) == 0) foreach ($calendars as $c) {
|
||||
$prop = $c->getProperties(array("id"));
|
||||
$calendars_selected[] = $prop["id"];
|
||||
}
|
||||
|
||||
$opts = array(
|
||||
"view" => $view,
|
||||
"theme" => $theme,
|
||||
|
@ -96,12 +146,13 @@ function wdcal_printCalendar($calendars, $calendar_preselected, $data_feed_url,
|
|||
<div id="animexxcalendar" class="animexxcalendar">
|
||||
<div class="calselect"><strong>Available Calendars:</strong>';
|
||||
|
||||
foreach ($cals_avail as $cal) {
|
||||
$x .= '<label style="margin-left: 10px; margin-right: 10px;"><input type="checkbox" name="cals[]" value="' . $cal["ns"] . '-' . $cal["id"] . '"';
|
||||
foreach ($calendars as $cal) {
|
||||
$cal_id = $cal->getProperties(array("id", DAV_DISPLAYNAME));
|
||||
$x .= '<label style="margin-left: 10px; margin-right: 10px;"><input type="checkbox" name="cals[]" value="' . $cal_id["id"] . '"';
|
||||
$found = false;
|
||||
foreach ($calendar_preselected as $pre) if ($pre["ns"] == $cal["ns"] && $pre["id"] == $cal["id"]) $found = true;
|
||||
foreach ($calendars_selected as $pre) if ($pre["id"] == $cal_id["id"]) $found = true;
|
||||
if ($found) $x .= ' checked';
|
||||
$x .= '> ' . escape_tags($cal["displayname"]) . '</label> ';
|
||||
$x .= '> ' . escape_tags($cal_id[DAV_DISPLAYNAME]) . '</label> ';
|
||||
}
|
||||
|
||||
$x .= '</div>
|
||||
|
@ -179,166 +230,57 @@ function wdcal_printCalendar($calendars, $calendar_preselected, $data_feed_url,
|
|||
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param int $calendar_id
|
||||
* @param int $calendarobject_id
|
||||
* @param string $recurr_uri
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_getDetailPage($uri, $recurr_uri)
|
||||
function wdcal_getDetailPage($calendar_id, $calendarobject_id, $recurr_uri)
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
try {
|
||||
$details = null;
|
||||
$cals = dav_getMyCals($a->user["uid"]);
|
||||
foreach ($cals as $c) {
|
||||
$cs = wdcal_calendar_factory($a->user["uid"], $c->namespace, $c->namespace_id);
|
||||
$p = $cs->getPermissionsItem($a->user["uid"], $uri, $recurr_uri);
|
||||
if ($p["read"]) try {
|
||||
$redirect = $cs->getItemDetailRedirect($uri);
|
||||
if ($redirect !== null) goaway($redirect);
|
||||
$details = $cs->getItemByUri($uri);
|
||||
$server = dav_create_server(true, true, false);
|
||||
$cal = dav_get_current_user_calendar_by_id($server, $calendar_id, DAV_ACL_READ);
|
||||
$obj = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($calendarobject_id);
|
||||
dav_get_current_user_calendarobject($server, $cal, $obj["uri"], DAV_ACL_READ); // Check permissions
|
||||
|
||||
$calbackend = wdcal_calendar_factory_by_id($calendar_id);
|
||||
$redirect = $calbackend->getItemDetailRedirect($calendar_id, $calendarobject_id);
|
||||
|
||||
if ($redirect !== null) goaway($a->get_baseurl() . $redirect);
|
||||
|
||||
$details = $obj;
|
||||
} catch (Exception $e) {
|
||||
notification(t("Error") . ": " . $e);
|
||||
info(t("Error") . ": " . $e);
|
||||
goaway($a->get_baseurl() . "/dav/wdcal/");
|
||||
}
|
||||
|
||||
return print_r($details, true);
|
||||
}
|
||||
|
||||
|
||||
return $uri . " / " . $recurr_uri . "<br>" . print_r($details, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param int $calendar_id
|
||||
* @param int $uri
|
||||
* @param string $recurr_uri
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_getEditPage($uri, $recurr_uri = "")
|
||||
function wdcal_getEditPage($calendar_id, $uri, $recurr_uri = "")
|
||||
{
|
||||
|
||||
$a = get_app();
|
||||
$localization = wdcal_local::getInstanceByUser($a->user["uid"]);
|
||||
|
||||
if ($uri != "" && $uri != "new") {
|
||||
$o = q("SELECT * FROM %s%sjqcalendar WHERE `uid` = %d AND `ical_uri` = '%s' AND `ical_recurr_uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $a->user["uid"], dbesc($uri), dbesc($recurr_uri)
|
||||
);
|
||||
if (count($o) != 1) return t('Not found');
|
||||
$event = $o[0];
|
||||
|
||||
$calendarSource = wdcal_calendar_factory($a->user["uid"], $event["namespace"], $event["namespace_id"]);
|
||||
|
||||
$permissions = $calendarSource->getPermissionsItem($a->user["uid"], $uri, $recurr_uri, $event);
|
||||
|
||||
if (!$permissions["write"]) return t('No access');
|
||||
|
||||
$n = q("SELECT * FROM %s%snotifications WHERE `uid` = %d AND `ical_uri` = '%s' AND `ical_recurr_uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $a->user["uid"], dbesc($uri), dbesc($recurr_uri)
|
||||
);
|
||||
if (count($n) > 0) {
|
||||
$notification_type = $n[0]["rel_type"];
|
||||
$notification_value = -1 * $n[0]["rel_value"];
|
||||
$notification = true;
|
||||
} else {
|
||||
if ($event["IsAllDayEvent"]) {
|
||||
$notification_type = "hour";
|
||||
$notification_value = 24;
|
||||
} else {
|
||||
$notification_type = "minute";
|
||||
$notification_value = 60;
|
||||
}
|
||||
$notification = false;
|
||||
return wdcal_getEditPage_str($localization, $a->get_baseurl(), $a->user["uid"], $calendar_id, $uri, $recurr_uri);
|
||||
}
|
||||
|
||||
function wdcal_getNewPage()
|
||||
{
|
||||
$a = get_app();
|
||||
$localization = wdcal_local::getInstanceByUser($a->user["uid"]);
|
||||
|
||||
} elseif (isset($_REQUEST["start"]) && $_REQUEST["start"] > 0) {
|
||||
$event = array(
|
||||
"id" => 0,
|
||||
"Subject" => $_REQUEST["title"],
|
||||
"Location" => "",
|
||||
"Description" => "",
|
||||
"StartTime" => wdcal_php2MySqlTime($_REQUEST["start"]),
|
||||
"EndTime" => wdcal_php2MySqlTime($_REQUEST["end"]),
|
||||
"IsAllDayEvent" => $_REQUEST["isallday"],
|
||||
"Color" => null,
|
||||
"RecurringRule" => null,
|
||||
);
|
||||
if ($_REQUEST["isallday"]) {
|
||||
$notification_type = "hour";
|
||||
$notification_value = 24;
|
||||
} else {
|
||||
$notification_type = "hour";
|
||||
$notification_value = 1;
|
||||
}
|
||||
|
||||
$notification = true;
|
||||
} else {
|
||||
$event = array(
|
||||
"id" => 0,
|
||||
"Subject" => "",
|
||||
"Location" => "",
|
||||
"Description" => "",
|
||||
"StartTime" => date("Y-m-d H:i:s"),
|
||||
"EndTime" => date("Y-m-d H:i:s", time() + 3600),
|
||||
"IsAllDayEvent" => "0",
|
||||
"Color" => "#5858ff",
|
||||
"RecurringRule" => null,
|
||||
);
|
||||
$notification_type = "hour";
|
||||
$notification_value = 1;
|
||||
$notification = true;
|
||||
}
|
||||
|
||||
$postto = $a->get_baseurl() . "/dav/wdcal/" . ($uri == "new" ? "new/" : $uri . "/edit/");
|
||||
|
||||
$out = "<a href='" . $a->get_baseurl() . "/dav/wdcal/'>" . t("Go back to the calendar") . "</a><br><br>";
|
||||
$out .= "<form method='POST' action='$postto'><input type='hidden' name='form_security_token' value='" . get_form_security_token('caledit') . "'>\n";
|
||||
|
||||
$out .= "<label for='cal_subject'>Subject:</label>
|
||||
<input name='color' id='cal_color' value='" . (strlen($event["Color"]) != 7 ? "#5858ff" : escape_tags($event["Color"])) . "'>
|
||||
<input name='subject' id='cal_subject' value='" . escape_tags($event["Subject"]) . "'><br>\n";
|
||||
$out .= "<label for='cal_allday'>Is All-Day event:</label><input type='checkbox' name='allday' id='cal_allday' " . ($event["IsAllDayEvent"] ? "checked" : "") . "><br>\n";
|
||||
|
||||
$out .= "<label for='cal_startdate'>" . t("Starts") . ":</label>";
|
||||
$out .= "<input name='start_date' value='" . $localization->dateformat_datepicker_php(wdcal_mySql2PhpTime($event["StartTime"])) . "' id='cal_start_date'>";
|
||||
$out .= "<input name='start_time' value='" . substr($event["StartTime"], 11, 5) . "' id='cal_start_time'>";
|
||||
$out .= "<br>\n";
|
||||
|
||||
$out .= "<label for='cal_enddate'>" . t("Ends") . ":</label>";
|
||||
$out .= "<input name='end_date' value='" . $localization->dateformat_datepicker_php(wdcal_mySql2PhpTime($event["EndTime"])) . "' id='cal_end_date'>";
|
||||
$out .= "<input name='end_time' value='" . substr($event["EndTime"], 11, 5) . "' id='cal_end_time'>";
|
||||
$out .= "<br>\n";
|
||||
|
||||
$out .= "<label for='cal_location'>" . t("Location") . ":</label><input name='location' id='cal_location' value='" . escape_tags($event["Location"]) . "'><br>\n";
|
||||
|
||||
$out .= "<label for='event-desc-textarea'>" . t("Description") . ":</label> <textarea id='event-desc-textarea' name='wdcal_desc' style='vertical-align: top; width: 400px; height: 100px;'>" . escape_tags($event["Description"]) . "</textarea>";
|
||||
$out .= "<br style='clear: both;'>";
|
||||
|
||||
$out .= "<label for='notification'>" . t('Notification') . ":</label>";
|
||||
$out .= '<input type="checkbox" name="notification" id="notification" ';
|
||||
if ($notification) $out .= "checked";
|
||||
$out .= '> ';
|
||||
$out .= '<span id="notification_detail" style="display: none;">
|
||||
<input name="notification_value" value="' . $notification_value . '" size="3">
|
||||
<select name="notification_type" size="1">
|
||||
<option value="minute" ';
|
||||
if ($notification_type == "minute") $out .= "selected";
|
||||
$out .= '> ' . t('Minutes') . '</option>
|
||||
<option value="hour" ';
|
||||
if ($notification_type == "hour") $out .= "selected";
|
||||
$out .= '> ' . t('Hours') . '</option>
|
||||
<option value="day" ';
|
||||
if ($notification_type == "day") echo "selected";
|
||||
$out .= '> ' . t('Days') . '</option>
|
||||
</select> ' . t('before') . '
|
||||
</span><br><br>';
|
||||
|
||||
|
||||
$out .= "<script>\$(function() {
|
||||
wdcal_edit_init('" . $localization->dateformat_datepicker_js() . "');
|
||||
});</script>";
|
||||
|
||||
$out .= "<input type='submit' name='save' value='Save'></form>";
|
||||
|
||||
return $out;
|
||||
return wdcal_getEditPage_str($localization, $a->get_baseurl(), $a->user["uid"], 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
|
130
dav/main.php
130
dav/main.php
|
@ -24,12 +24,6 @@ function dav_module()
|
|||
|
||||
function dav_include_files()
|
||||
{
|
||||
require_once (__DIR__ . "/common/dbclasses/dbclass_animexx.class.php");
|
||||
require_once (__DIR__ . "/common/dbclasses/dbclass.friendica.calendars.class.php");
|
||||
require_once (__DIR__ . "/common/dbclasses/dbclass.friendica.jqcalendar.class.php");
|
||||
require_once (__DIR__ . "/common/dbclasses/dbclass.friendica.notifications.class.php");
|
||||
require_once (__DIR__ . "/common/dbclasses/dbclass.friendica.calendarobjects.class.php");
|
||||
|
||||
/*
|
||||
require_once (__DIR__ . "/SabreDAV/lib/Sabre.includes.php");
|
||||
require_once (__DIR__ . "/SabreDAV/lib/Sabre/VObject/includes.php");
|
||||
|
@ -38,31 +32,27 @@ function dav_include_files()
|
|||
*/
|
||||
require_once (__DIR__ . "/SabreDAV/lib/Sabre/autoload.php");
|
||||
|
||||
$tz_before = date_default_timezone_get();
|
||||
require_once (__DIR__ . "/iCalcreator/iCalcreator.class.php");
|
||||
date_default_timezone_set($tz_before);
|
||||
|
||||
require_once (__DIR__ . "/common/calendar.fnk.php");
|
||||
require_once (__DIR__ . "/common/calendar_rendering.fnk.php");
|
||||
require_once (__DIR__ . "/common/dav_caldav_backend_common.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_caldav_backend.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_caldav_backend_private.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_caldav_backend_virtual.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_caldav_root.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_user_calendars.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_carddav_root.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_carddav_backend_std.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_user_addressbooks.inc.php");
|
||||
require_once (__DIR__ . "/common/virtual_cal_source_backend.inc.php");
|
||||
require_once (__DIR__ . "/common/dav_caldav_calendar_virtual.inc.php");
|
||||
require_once (__DIR__ . "/common/wdcal_configuration.php");
|
||||
require_once (__DIR__ . "/common/wdcal_cal_source.inc.php");
|
||||
require_once (__DIR__ . "/common/wdcal_cal_source_private.inc.php");
|
||||
require_once (__DIR__ . "/common/wdcal_backend.inc.php");
|
||||
|
||||
require_once (__DIR__ . "/dav_friendica_principal.inc.php");
|
||||
require_once (__DIR__ . "/dav_friendica_auth.inc.php");
|
||||
require_once (__DIR__ . "/dav_carddav_backend_friendica_community.inc.php");
|
||||
require_once (__DIR__ . "/dav_caldav_backend_friendica.inc.php");
|
||||
require_once (__DIR__ . "/virtual_cal_source_friendica.inc.php");
|
||||
require_once (__DIR__ . "/wdcal_cal_source_friendicaevents.inc.php");
|
||||
require_once (__DIR__ . "/dav_carddav_backend_virtual_friendica.inc.php");
|
||||
require_once (__DIR__ . "/dav_caldav_backend_virtual_friendica.inc.php");
|
||||
require_once (__DIR__ . "/FriendicaACLPlugin.inc.php");
|
||||
|
||||
require_once (__DIR__ . "/common/wdcal_edit.inc.php");
|
||||
require_once (__DIR__ . "/calendar.friendica.fnk.php");
|
||||
require_once (__DIR__ . "/layout.fnk.php");
|
||||
}
|
||||
|
@ -81,7 +71,7 @@ function dav_init(&$a)
|
|||
|
||||
dav_include_files();
|
||||
|
||||
if (false) {
|
||||
if (true) {
|
||||
dbg(true);
|
||||
error_reporting(E_ALL);
|
||||
ini_set("display_errors", 1);
|
||||
|
@ -102,58 +92,24 @@ function dav_init(&$a)
|
|||
}
|
||||
return;
|
||||
}
|
||||
if ($a->argc >= 2 && $a->argv[1] == "getExceptionDates") {
|
||||
echo wdcal_getEditPage_exception_selector();
|
||||
killme();
|
||||
}
|
||||
|
||||
if ($a->argc >= 2 && $a->argv[1] == "settings") {
|
||||
return;
|
||||
}
|
||||
|
||||
$authBackend = new Sabre_DAV_Auth_Backend_Friendica();
|
||||
$principalBackend = new Sabre_DAVACL_PrincipalBackend_Friendica($authBackend);
|
||||
$caldavBackend_std = new Sabre_CalDAV_Backend_Std();
|
||||
$caldavBackend_community = new Sabre_CalDAV_Backend_Friendica();
|
||||
$carddavBackend_std = new Sabre_CardDAV_Backend_Std();
|
||||
$carddavBackend_community = new Sabre_CardDAV_Backend_FriendicaCommunity();
|
||||
|
||||
if (isset($_SERVER["PHP_AUTH_USER"])) {
|
||||
$tree = new Sabre_DAV_SimpleCollection('root', array(
|
||||
new Sabre_DAV_SimpleCollection('principals', array(
|
||||
new Sabre_CalDAV_Principal_Collection($principalBackend, "principals/users"),
|
||||
)),
|
||||
new Sabre_CalDAV_AnimexxCalendarRootNode($principalBackend, array(
|
||||
$caldavBackend_std,
|
||||
$caldavBackend_community,
|
||||
)),
|
||||
new Sabre_CardDAV_AddressBookRootFriendica($principalBackend, array(
|
||||
$carddavBackend_std,
|
||||
$carddavBackend_community,
|
||||
)),
|
||||
));
|
||||
} else {
|
||||
$tree = new Sabre_DAV_SimpleCollection('root', array());
|
||||
if (isset($_REQUEST["test"])) {
|
||||
renderAllCalDavEntries();
|
||||
}
|
||||
|
||||
// The object tree needs in turn to be passed to the server class
|
||||
$server = new Sabre_DAV_Server($tree);
|
||||
|
||||
$url = parse_url($a->get_baseurl());
|
||||
$server->setBaseUri(CALDAV_URL_PREFIX);
|
||||
|
||||
$authPlugin = new Sabre_DAV_Auth_Plugin($authBackend, 'SabreDAV');
|
||||
$server->addPlugin($authPlugin);
|
||||
|
||||
$aclPlugin = new Sabre_DAVACL_Plugin_Friendica();
|
||||
$aclPlugin->defaultUsernamePath = "principals/users";
|
||||
$server->addPlugin($aclPlugin);
|
||||
|
||||
$caldavPlugin = new Sabre_CalDAV_Plugin();
|
||||
$server->addPlugin($caldavPlugin);
|
||||
|
||||
$carddavPlugin = new Sabre_CardDAV_Plugin();
|
||||
$server->addPlugin($carddavPlugin);
|
||||
|
||||
$server = dav_create_server();
|
||||
$browser = new Sabre_DAV_Browser_Plugin();
|
||||
$server->addPlugin($browser);
|
||||
|
||||
$server->exec();
|
||||
|
||||
killme();
|
||||
|
@ -174,36 +130,44 @@ function dav_content()
|
|||
if ($a->argv[1] == "settings") {
|
||||
return wdcal_getSettingsPage($a);
|
||||
} elseif ($a->argv[1] == "wdcal") {
|
||||
if ($a->argc >= 3 && strlen($a->argv[2]) > 0) {
|
||||
$uri = $a->argv[2];
|
||||
|
||||
if ($uri == "new") {
|
||||
if (isset($a->argv[2]) && strlen($a->argv[2]) > 0) {
|
||||
if ($a->argv[2] == "ics") {
|
||||
wdcal_print_user_ics();
|
||||
} elseif ($a->argv[2] == "new") {
|
||||
$o = "";
|
||||
if (isset($_REQUEST["save"])) {
|
||||
check_form_security_token_redirectOnErr($a->get_baseurl() . "/dav/wdcal/", "caledit");
|
||||
$o .= wdcal_postEditPage("new", "", $a->user["uid"], $a->timezone, $a->get_baseurl() . "/dav/wdcal/");
|
||||
$ret = wdcal_postEditPage("new", "", $a->user["uid"], $a->timezone, $a->get_baseurl() . "/dav/wdcal/");
|
||||
if ($ret["ok"]) notice($ret["msg"]);
|
||||
else info($ret["msg"]);
|
||||
}
|
||||
$o .= wdcal_getEditPage("new");
|
||||
$o .= wdcal_getNewPage();
|
||||
return $o;
|
||||
} else {
|
||||
$calendar_id = IntVal($a->argv[2]);
|
||||
if (isset($a->argv[3]) && $a->argv[3] > 0) {
|
||||
$recurr_uri = ""; // @TODO
|
||||
if (isset($a->argv[3]) && $a->argv[3] == "edit") {
|
||||
if (isset($a->argv[4]) && $a->argv[4] == "edit") {
|
||||
$o = "";
|
||||
if (isset($_REQUEST["save"])) {
|
||||
check_form_security_token_redirectOnErr($a->get_baseurl() . "/dav/wdcal/", "caledit");
|
||||
$o .= wdcal_postEditPage($uri, $recurr_uri, $a->user["uid"], $a->timezone, $a->get_baseurl() . "/dav/wdcal/");
|
||||
$ret = wdcal_postEditPage($a->argv[3], $recurr_uri, $a->user["uid"], $a->timezone, $a->get_baseurl() . "/dav/wdcal/");
|
||||
if ($ret["ok"]) notice($ret["msg"]);
|
||||
else info($ret["msg"]);
|
||||
}
|
||||
$o .= wdcal_getEditPage($uri, $recurr_uri);
|
||||
$o .= wdcal_getEditPage($calendar_id, $a->argv[3], $recurr_uri);
|
||||
return $o;
|
||||
} else {
|
||||
return wdcal_getDetailPage($uri, $recurr_uri);
|
||||
return wdcal_getDetailPage($calendar_id, $a->argv[3], $recurr_uri);
|
||||
}
|
||||
} else {
|
||||
// @TODO Edit Calendar
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$cals = dav_getMyCals($a->user["uid"]);
|
||||
$cals_show = array();
|
||||
foreach ($cals as $e) $cals_show[] = array("ns" => $e->namespace, "id" => $e->namespace_id, "displayname" => $e->displayname);
|
||||
$x = wdcal_printCalendar($cals, $cals_show, $a->get_baseurl() . "/dav/wdcal/feed/", "week", 0, 200);
|
||||
$server = dav_create_server(true, true, false);
|
||||
$cals = dav_get_current_user_calendars($server, DAV_ACL_READ);
|
||||
$x = wdcal_printCalendar($cals, array(), $a->get_baseurl() . "/dav/wdcal/feed/", "week", 0, 200);
|
||||
}
|
||||
}
|
||||
return $x;
|
||||
|
@ -218,8 +182,8 @@ function dav_event_created_hook(&$a, &$b)
|
|||
{
|
||||
dav_include_files();
|
||||
// @TODO Updating the cache instead of completely invalidating and rebuilding it
|
||||
FriendicaVirtualCalSourceBackend::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_CONTACTS);
|
||||
FriendicaVirtualCalSourceBackend::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_MINE);
|
||||
Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_CONTACTS);
|
||||
Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_MINE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,8 +194,8 @@ function dav_event_updated_hook(&$a, &$b)
|
|||
{
|
||||
dav_include_files();
|
||||
// @TODO Updating the cache instead of completely invalidating and rebuilding it
|
||||
FriendicaVirtualCalSourceBackend::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_CONTACTS);
|
||||
FriendicaVirtualCalSourceBackend::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_MINE);
|
||||
Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_CONTACTS);
|
||||
Sabre_CalDAV_Backend_Friendica::invalidateCache($a->user["uid"], CALDAV_FRIENDICA_MINE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,6 +220,7 @@ function dav_plugin_admin_post(&$a = null, &$o = null)
|
|||
{
|
||||
check_form_security_token_redirectOnErr('/admin/plugins/dav', 'dav_admin_save');
|
||||
|
||||
dav_include_files();
|
||||
require_once(__DIR__ . "/database-init.inc.php");
|
||||
|
||||
if (isset($_REQUEST["install"])) {
|
||||
|
@ -263,15 +228,20 @@ function dav_plugin_admin_post(&$a = null, &$o = null)
|
|||
if (count($errs) == 0) info(t('The database tables have been installed.') . EOL);
|
||||
else notice(t("An error occurred during the installation.") . EOL);
|
||||
}
|
||||
if (isset($_REQUEST["upgrade"])) {
|
||||
$errs = dav_upgrade_tables();
|
||||
if (count($errs) == 0) info(t('The database tables have been updated.') . EOL);
|
||||
else notice(t("An error occurred during the update.") . EOL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param App $a
|
||||
* @param null|object $o
|
||||
* @param string $o
|
||||
*/
|
||||
function dav_plugin_admin(&$a, &$o)
|
||||
{
|
||||
|
||||
dav_include_files();
|
||||
require_once(__DIR__ . "/database-init.inc.php");
|
||||
|
||||
$dbstatus = dav_check_tables();
|
||||
|
|
|
@ -11,3 +11,33 @@ div.colorPicker-picker { display: inline-block; }
|
|||
.ui-datepicker select.ui-datepicker-year { min-width: 0; width: 50px !important; }
|
||||
#cal_start_time, #cal_end_time { width: 5em; margin-left: 1em; }
|
||||
#cal_start_date, #cal_end_date { width: 6em;}
|
||||
|
||||
|
||||
label.block {
|
||||
background: none repeat scroll 0 0 #CCCCCC;
|
||||
border: 1px solid #EEEEEC;
|
||||
box-shadow: 3px 3px 5px 0 #111111;
|
||||
color: #111111;
|
||||
display: inline-block;
|
||||
font-size: small;
|
||||
margin: 0 10px 1em 0;
|
||||
padding: 3px 5px;
|
||||
width: 38%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
label.plain {
|
||||
background: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
color: black;
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.rec_exceptions { display: inline-block; }
|
||||
.rec_exceptions_holder { display: inline-block; }
|
||||
.rec_exceptions .remover { }
|
||||
#rec_until_count { width: 50px; }
|
||||
#rec_until_date { width: 100px; }
|
Loading…
Reference in a new issue