Esempio n. 1
0
        /// <summary>
        ///     Used to build a response with an error
        /// </summary>
        /// <param name="response">The response that comes from the controller</param>
        /// <param name="errorMessage">The message to put in the error.</param>
        /// <param name="errorCode">The code of the error.</param>
        /// <param name="href">The requested href.</param>
        /// <returns></returns>
        private async Task ReturnError(HttpResponse response, string errorMessage, int errorCode, string href)
        {
            //build the root of the xml
            var multistatusNode = new XmlTreeStructure("multistatus", "DAV:")
            {
                Namespaces = new Dictionary <string, string>
                {
                    { "D", "DAV:" },
                    { "C", "urn:ietf:params:xml:ns:caldav" }
                }
            };

            //each returned resource has is own response and href nodes
            var responseNode = new XmlTreeStructure("response", "DAV:");
            var hrefNode     = new XmlTreeStructure("href", "DAV:");

            hrefNode.AddValue(href);

            //href is a child pf response
            responseNode.AddChild(hrefNode);

            IXMLTreeStructure statusNode = new XmlTreeStructure("status", "DAV:");

            statusNode.AddValue($"HTTP/1.1 {errorCode} {errorMessage}");
            responseNode.AddChild(statusNode);

            multistatusNode.AddChild(responseNode);

            await response.WriteAsync(multistatusNode.ToString());
        }
Esempio n. 2
0
        /// <summary>
        ///     Take the calendar that passed the filter and
        ///     create the multi-status xml.
        /// </summary>
        /// <param name="resources">The resources to be returned</param>
        /// <param name="calDataNode">
        ///     THis is the node with name ="prop"
        ///     When used in a calendaring REPORT request, the CALDAV:calendar-data XML
        ///     element specifies which parts of calendar object resources need to be returned in the
        ///     response.If the CALDAV:calendar-data XML element doesn't contain any
        ///     CALDAV:comp element, calendar object resources will be returned in their entirety.
        /// </param>
        /// <param name="httpContext"></param>
        /// <returns>The string representation of the multi-status Xml with the results.</returns>
        public async Task ReportResponseBuilder(IEnumerable <KeyValuePair <string, VCalendar> > resources,
                                                IXMLTreeStructure calDataNode, HttpContext httpContext)
        {
            var multistatusNode = new XmlTreeStructure("multistatus", "DAV:")
            {
                Namespaces = new Dictionary <string, string>
                {
                    { "D", "DAV:" },
                    { "C", "urn:ietf:params:xml:ns:caldav" }
                }
            };

            //take the node that specified the comp and properties
            //to return


            foreach (var resource in resources)
            {
                IXMLTreeStructure statusNode;

                //each returned resource has is own response and nodes
                var responseNode = new XmlTreeStructure("response", "DAV:");
                var hrefNode     = new XmlTreeStructure("href", "DAV:");
                var href         = resource.Key[0] != '/' ? "/" + resource.Key : resource.Key;
                hrefNode.AddValue(href);

                //href is a child pf response
                responseNode.AddChild(hrefNode);

                //if the resource is null it was not foound so
                // add an error status
                if (resource.Value == null)
                {
                    statusNode = new XmlTreeStructure("status", "DAV:");
                    statusNode.AddValue("HTTP/1.1 404 Not Found");
                    responseNode.AddChild(statusNode);
                }
                else
                {
                    var propstatNode = new XmlTreeStructure("propstat", "DAV:");

                    //that the requested data
                    var propStats = await ProccessPropNode(calDataNode, resource);


                    foreach (var propStat in propStats)
                    {
                        responseNode.AddChild(propStat);
                    }
                }

                multistatusNode.AddChild(responseNode);
            }
            var responseText  = multistatusNode.ToString();
            var responseBytes = Encoding.UTF8.GetBytes(responseText);

            httpContext.Response.ContentLength = responseBytes.Length;
            await httpContext.Response.Body.WriteAsync(responseBytes, 0, responseBytes.Length);
        }
Esempio n. 3
0
        public async Task AllPropMethod(string url, string calendarResourceId, int?depth,
                                        List <KeyValuePair <string, string> > aditionalProperties, XmlTreeStructure multistatusTree)
        {
            //error flag

            //Here it is created the response body for the collection or resource
            //It depends if calendarResourceId == null.
            var primaryResponse = await AllPropFillTree(url, calendarResourceId, aditionalProperties);

            //The response body is added to the result xml tree.
            multistatusTree.AddChild(primaryResponse);

            //check if there was any error
            IXMLTreeStructure errorNode;
            var errorOcurred = primaryResponse.GetChildAtAnyLevel("responsedescription", out errorNode);

            //Now I start putting all objectResource responses if the primary target was a collection
            //and if depth is greater than depth 0.

            #region Adding the responses for resources.

            if (calendarResourceId == null && depth == 1 || depth == -1)
            {
                var collection = _collectionRepository.Get(url);

                foreach (var calendarResource in collection.CalendarResources)
                {
                    //For every resource in the collection it is added a new xml "response"
                    var resourceResponse = await AllPropFillTree(url + calendarResource.Name, calendarResource.Name,
                                                                 aditionalProperties);

                    multistatusTree.AddChild(resourceResponse);

                    //error check
                    if (!errorOcurred)
                    {
                        errorOcurred = resourceResponse.GetChildAtAnyLevel("responsedescription", out errorNode);
                    }
                }
            }
            if (errorOcurred)
            {
                //if an error occured it is added a new "responsedescription" with a message of the error
                //to the root of the tree. That is the "multistatus" xml.
                errorNode = new XmlTreeStructure("responsedescription", "DAV:");
                errorNode.AddValue("There has been an error");
                multistatusTree.AddChild(errorNode);
            }

            #endregion
        }
Esempio n. 4
0
        /// <summary>
        ///     Build the xml of the body and write
        ///     its string representation to the HttpRespose.Body
        /// </summary>
        /// <param name="response">The response of the request.</param>
        /// <param name="principalsAndProperties">The principals with its properties.</param>
        /// <returns></returns>
        public async Task WriteBody(HttpResponse response,
                                    Dictionary <Principal, IEnumerable <Property> > principalsAndProperties)
        {
            //build the root of the xml
            var multistatusNode = new XmlTreeStructure("multistatus", "DAV:")
            {
                Namespaces = new Dictionary <string, string>
                {
                    { "D", "DAV:" },
                    { "C", "urn:ietf:params:xml:ns:caldav" }
                }
            };

            //take the node that specified the comp and properties
            //to return

            foreach (var pp in principalsAndProperties)
            {
                IXMLTreeStructure statusNode;

                //each returned resource has is own response and href nodes
                var responseNode = new XmlTreeStructure("response", "DAV:");
                var hrefNode     = new XmlTreeStructure("href", "DAV:");
                hrefNode.AddValue(pp.Key.PrincipalURL);

                //href is a child pf response
                responseNode.AddChild(hrefNode);

                //if the resource is null it was not foound so
                // add an error status
                if (pp.Value == null)
                {
                    statusNode = new XmlTreeStructure("status", "DAV:");
                    statusNode.AddValue("HTTP/1.1 404 Not Found");
                    responseNode.AddChild(statusNode);
                }
                else
                {
                    var propstatNode = new XmlTreeStructure("propstat", "DAV:");
                    var propNode     = new XmlTreeStructure("prop", "DAV:");
                    //add the properties to the prop node.
                    foreach (var property in pp.Value)
                    {
                        propNode.AddChild(XmlTreeStructure.Parse(property.Value));
                    }

                    propstatNode.AddChild(propNode);
                    //adding the status node
                    // TODO: check the status!!
                    statusNode = new XmlTreeStructure("status", "DAV:");
                    statusNode.AddValue("HTTP/1.1 200 OK");

                    propstatNode.AddChild(statusNode);

                    responseNode.AddChild(propstatNode);
                }

                multistatusNode.AddChild(responseNode);
                await response.WriteAsync(multistatusNode.ToString());
            }
        }
Esempio n. 5
0
        /// <summary>
        ///     Returns a Response XML tree for a prop request with all the property names
        ///     and property values specified in the request.
        /// </summary>
        /// <param name="url"></param>
        /// <param name="calendarResourceId">Name of the resource</param>
        /// <param name="propertiesNameNamespace">List of requested properties (key=name; value=namespace)</param>
        /// <param name="principal"></param>
        /// <returns></returns>
        private async Task <XmlTreeStructure> PropFillTree(string url, string calendarResourceId,
                                                           List <KeyValuePair <string, string> > propertiesNameNamespace, Principal principal)
        {
            //a "response xml element is added for each collection or resource"

            #region Adding the response of the collection or resource.

            var treeChild = new XmlTreeStructure("response", "DAV:");

            #region Adding the <D:href>/api/v1/caldav/{userEmail}/calendars/{collectionName}/{calendarResourceId}?</D:href>

            //an href with the corresponding url is added to the response
            var href = new XmlTreeStructure("href", "DAV:");
            href.AddValue(SystemProperties._baseUrl + url);

            treeChild.AddChild(href);

            #endregion

            #region Adding the propstats

            #region Selecting properties

            CalendarCollection collection;
            CalendarResource   resource;
            var propertiesCol   = new List <XmlTreeStructure>();
            var propertiesOk    = new List <XmlTreeStructure>();
            var propertiesWrong = new List <XmlTreeStructure>();
            var errorStack      = new Stack <string>();

            //the current-user-privilege-set is generated per request
            //it needs the DAV:acl property and the principalID
            Property aclProperty = null;

            //It take the list of requested properties and tries to get the corresponding property from db.
            //The methods are called for a resource or a collection accordingly its circumstances.
            //The properties are stored inside the propertiesCol. Where if the value is null it means that the collection could not be
            //retrieve.
            if (calendarResourceId == null)
            {
                collection = _collectionRepository.Get(url);
                if (propertiesNameNamespace != null)
                {
                    foreach (var addProperty in propertiesNameNamespace)
                    {
                        //gets the property from database
                        var property = await _collectionRepository.GetProperty(url, addProperty);

                        //Builds the xmlTreeExtructure checking that if the value is null thats because
                        //the property was not found.
                        IXMLTreeStructure prop;
                        if (property != null)
                        {
                            prop = property.Value == null
                                ? new XmlTreeStructure(property.Name, property.Namespace)
                            {
                                Value = ""
                            }
                        }
                        : XmlTreeStructure.Parse(property.Value);
                        else
                        {
                            prop = new XmlTreeStructure(addProperty.Key, addProperty.Value);
                        }
                        propertiesCol.Add((XmlTreeStructure)prop);
                    }
                    //take the acl property
                    aclProperty = collection.Properties.FirstOrDefault(x => x.Name == "acl");
                }
            }
            else
            {
                resource = _resourceRespository.Get(url);
                if (propertiesNameNamespace != null)
                {
                    foreach (var addProperty in propertiesNameNamespace)
                    {
                        //gets the property from database
                        var property = await _resourceRespository.GetProperty(url, addProperty);

                        //Builds the xmlTreeExtructure checking that if the value is null thats because
                        //the property was not found.
                        IXMLTreeStructure prop;
                        if (property != null)
                        {
                            prop = property.Value == null
                                ? new XmlTreeStructure(property.Name, property.Namespace)
                            {
                                Value = ""
                            }
                        }
                        : XmlTreeStructure.Parse(property.Value);
                        else
                        {
                            prop = new XmlTreeStructure(addProperty.Key, addProperty.Value);
                        }
                        propertiesCol.Add((XmlTreeStructure)prop);
                    }
                    //take the acl property
                    aclProperty = resource.Properties.FirstOrDefault(x => x.Name == "acl");
                }
            }

            //add the additional properties that are generated per request
            if (propertiesNameNamespace != null)
            {
                foreach (var pair in propertiesNameNamespace)
                {
                    switch (pair.Key)
                    {
                    case "current-user-privilege-set":
                        propertiesCol.RemoveAll(x => x.NodeName == pair.Key);
                        propertiesCol.Add(principal.GetCurrentUserPermissions(aclProperty));
                        break;
                    }
                }
            }


            //Here, properties are divided between recovered and error recovering
            foreach (var propTree in propertiesCol)
            {
                if (propTree.Value != null)
                {
                    propertiesOk.Add(propTree);
                }
                else
                {
                    propertiesWrong.Add(propTree);
                }
            }

            #endregion

            //For each returned status a "propstat" is created, containing a "prop" with all properties that belong to that current status.
            // And a "status" containing the message of the corresponding status.
            //Right Now there are only two "propstat" taking place OK and Wrong an therefore only two "status"
            //200 OK and 400 Not Found.
            //More should be added when ACL is working entairly.

            //TODO: Add the status forbidden for authentication permissions problems.

            #region Adding nested propOK

            var propstatOk = new XmlTreeStructure("propstat", "DAV:");
            var propOk     = new XmlTreeStructure("prop", "DAV:");

            //Here i add all properties to the prop.
            foreach (var property in propertiesOk)
            {
                propOk.AddChild(property);
            }

            propstatOk.AddChild(propOk);
            //This when i group the OK properties

            #region Adding nested status OK

            var statusOk = new XmlTreeStructure("status", "DAV:");
            statusOk.AddValue("HTTP/1.1 200 OK");
            propstatOk.AddChild(statusOk);

            #endregion

            #endregion

            //Here the same is made. The Wrong properties are grouped.

            #region Adding nested propWrong

            var propstatWrong = new XmlTreeStructure("propstat", "DAV:");
            var propWrong     = new XmlTreeStructure("prop", "DAV:");

            //Here i add all properties to the prop.
            foreach (var property in propertiesWrong)
            {
                propWrong.AddChild(property);
            }

            propstatWrong.AddChild(propWrong);

            #region Adding nested status Not Found

            var statusWrong = new XmlTreeStructure("status", "DAV:");
            statusWrong.AddValue("HTTP/1.1 400 Not Found");
            propstatWrong.AddChild(statusWrong);

            #endregion

            #region Adding responseDescription when wrong

            var responseDescrpWrong = new XmlTreeStructure("responsedescription", "DAV:");
            responseDescrpWrong.AddValue("The properties doesn't  exist");
            propstatWrong.AddChild(responseDescrpWrong);

            #endregion

            #endregion

            //If anyone of the property groups is empty it is not included in the response.
            if (propertiesOk.Count > 0)
            {
                treeChild.AddChild(propstatOk);
            }
            if (propertiesWrong.Count > 0)
            {
                treeChild.AddChild(propstatWrong);
            }

            #endregion

            return(treeChild);

            #endregion
        }
Esempio n. 6
0
        /// <summary>
        ///     Returns a Response XML element with all the property names
        ///     and property values of the visible properties.
        /// </summary>
        /// <param name="url"></param>
        /// <param name="calendarResourceId">Name of the resource</param>
        /// <param name="additionalProperties">List of additional requested properties (key=name; value=namespace)</param>
        /// <returns></returns>
        private async Task <XmlTreeStructure> AllPropFillTree(string url, string calendarResourceId,
                                                              List <KeyValuePair <string, string> > additionalProperties)
        {
            #region Adding the response of the collection or resource.

            //Adding standard structure for a "response" element.
            var treeChild = new XmlTreeStructure("response", "DAV:");

            #region Adding the <D:href>/api/v1/collections/users|groups/principalId/{collectionName}/{calendarResourceId}?</D:href>

            var href = new XmlTreeStructure("href", "DAV:");
            href.AddValue(SystemProperties._baseUrl + url);

            treeChild.AddChild(href);

            #endregion

            #region Adding the propstat

            #region Selecting properties

            var propertiesCol   = new List <XmlTreeStructure>();
            var propertiesOk    = new List <XmlTreeStructure>();
            var propertiesWrong = new List <XmlTreeStructure>();
            var errorStack      = new Stack <string>();

            //Here all visible properties are retrieve plus a collection of extra properties that can be
            //defined in the request body.

            if (calendarResourceId == null)
            {
                var properties = await _collectionRepository.GetAllProperties(url);

                foreach (var property in properties)
                {
                    //TODO: Check that the property is accessible beyond its visibility.
                    var tempTree = property.Value == null
                        ? new XmlTreeStructure(property.Name, property.Namespace)
                    {
                        Value = ""
                    }
                        : XmlTreeStructure.Parse(property.Value);

                    propertiesCol.Add((XmlTreeStructure)tempTree);
                }

                //looking for additional properties
                if (additionalProperties != null && additionalProperties.Count > 0)
                {
                    foreach (var addProperty in additionalProperties)
                    {
                        //gets the property from database
                        var property = await _collectionRepository.GetProperty(url, addProperty);

                        //Builds the xmlTreeExtructure checking that if the value is null thats because
                        //the property was not found.
                        IXMLTreeStructure prop;
                        if (property != null)
                        {
                            prop = property.Value == null
                                ? new XmlTreeStructure(property.Name, property.Namespace)
                            {
                                Value = ""
                            }
                        }
                        : XmlTreeStructure.Parse(property.Value);
                        else
                        {
                            prop = new XmlTreeStructure(addProperty.Key, addProperty.Value);
                        }
                        propertiesCol.Add((XmlTreeStructure)prop);
                    }
                }
            }
            else
            {
                var properties = await _resourceRespository.GetAllProperties(url);

                foreach (var property in properties)
                {
                    //TODO: Check that the property is accessible beyond its visibility.
                    var tempTree = property.Value == null
                        ? new XmlTreeStructure(property.Name, property.Namespace)
                    {
                        Value = ""
                    }
                        : XmlTreeStructure.Parse(property.Value);

                    propertiesCol.Add((XmlTreeStructure)tempTree);
                }

                //looking for additional properties
                if (additionalProperties != null && additionalProperties.Count > 0)
                {
                    foreach (var addProperty in additionalProperties)
                    {
                        //gets the property from database
                        var property = await _resourceRespository.GetProperty(url, addProperty);

                        //Builds the xmlTreeExtructure checking that if the value is null thats because
                        //the property was not found.
                        IXMLTreeStructure prop;
                        if (property != null)
                        {
                            prop = property.Value == null
                                ? new XmlTreeStructure(property.Name, property.Namespace)
                            {
                                Value = ""
                            }
                        }
                        : XmlTreeStructure.Parse(property.Value);
                        else
                        {
                            prop = new XmlTreeStructure(addProperty.Key, addProperty.Value);
                        }
                        propertiesCol.Add((XmlTreeStructure)prop);
                    }
                }
            }

            //Here there are divided all properties between recovered and error recovering
            foreach (var propTree in propertiesCol)
            {
                if (propTree.Value != null)
                {
                    propertiesOk.Add(propTree);
                }
                else
                {
                    propertiesWrong.Add(propTree);
                }
            }

            #endregion

            #region Adding nested propOK

            //This procedure has been explained in another method.
            //Here the retrieve properties are grouped.

            var propstatOk = new XmlTreeStructure("propstat", "DAV:");
            var propOk     = new XmlTreeStructure("prop", "DAV:");

            //Here i add all properties to the prop.
            foreach (var property in propertiesOk)
            {
                propOk.AddChild(property);
            }

            propstatOk.AddChild(propOk);

            #region Adding nested status OK

            var statusOk = new XmlTreeStructure("status", "DAV:");
            statusOk.AddValue("HTTP/1.1 200 OK");
            propstatOk.AddChild(statusOk);

            #endregion

            #endregion

            #region Adding nested propWrong

            //Here the properties that could not be retrieved are grouped.
            var propstatWrong = new XmlTreeStructure("propstat", "DAV:");
            var propWrong     = new XmlTreeStructure("prop", "DAV:");

            //Here i add all properties to the prop.
            foreach (var property in propertiesWrong)
            {
                propWrong.AddChild(property);
            }

            propstatWrong.AddChild(propWrong);

            #region Adding nested status Not Found

            var statusWrong = new XmlTreeStructure("status", "DAV:");
            statusWrong.AddValue("HTTP/1.1 400 Not Found");
            propstatWrong.AddChild(statusWrong);

            #endregion

            #region Adding responseDescription when wrong

            //Here i add an description for explain the errors.
            //This should be aplied in all method with an similar structure but for the moment is only used here.
            //However this is not required.
            var responseDescrpWrong = new XmlTreeStructure("responsedescription", "DAV:");
            responseDescrpWrong.AddValue("The properties doesn't  exist");
            propstatWrong.AddChild(responseDescrpWrong);

            #endregion

            #endregion

            //If any of the "status" group is empty, it is not included.
            if (propertiesOk.Count > 0)
            {
                treeChild.AddChild(propstatOk);
            }
            if (propertiesWrong.Count > 0)
            {
                treeChild.AddChild(propstatWrong);
            }

            #endregion

            return(treeChild);

            #endregion
        }
Esempio n. 7
0
        /// <summary>
        ///     Returns a Response XML element with the name of all properties
        ///     of a collection or resource.
        /// </summary>
        /// <param name="url"></param>
        /// <param name="calendarResourceId"></param>
        /// <returns></returns>
        private async Task <XmlTreeStructure> PropNameFillTree(string url, string calendarResourceId = null)
        {
            #region Adding the response of the collection or resource.

            //A "response" structure with all its children is build in this method.
            var treeChild = new XmlTreeStructure("response", "DAV:");

            #region Adding the <D:href>/api/v1/caldav/{userEmail}/calendars/{collectionName}/{calendarResourceId}?</D:href>

            var href = new XmlTreeStructure("href", "DAV:");
            href.AddValue(SystemProperties._baseUrl + url);

            treeChild.AddChild(href);

            #endregion

            #region Adding the propstat

            //in this section is where the "propstat" structure its build.
            var propstat = new XmlTreeStructure("propstat", "DAV:");

            #region Adding nested status

            //each "propstat" has a "status" with the message that define it.
            //"propname" is always "200 OK" because you are only accessing the name of the established properties.
            var status = new XmlTreeStructure("status", "DAV:");
            status.AddValue("HTTP/1.1 200 OK");
            propstat.AddChild(status);

            #endregion

            #region Adding nested prop

            var prop = new XmlTreeStructure("prop", "DAV:");
            List <XmlTreeStructure> properties;

            //Depending if the target is a collection or a resource this section
            //will find the object in the database and get from there all names of properties.
            if (calendarResourceId == null)
            {
                //var collection = _collectionRepository.Get(url).Result;
                properties =
                    (await _collectionRepository.GetAllPropname(url)).Select(p => new XmlTreeStructure(p.Key, p.Value))
                    .ToList();
                //properties = collection.GetAllPropertyNames();
            }
            else
            {
                properties =
                    (await _resourceRespository.GetAllPropname(url)).Select(p => new XmlTreeStructure(p.Key, p.Value))
                    .ToList();
            }

            //Here i add all properties to the prop.
            foreach (var property in properties)
            {
                prop.AddChild(property);
            }

            propstat.AddChild(prop);

            #endregion

            treeChild.AddChild(propstat);

            #endregion

            return(treeChild);

            #endregion
        }
Esempio n. 8
0
        /// <summary>
        ///     Take the prop node that specified the properties and
        ///     component that are requested, extract this data from
        ///     the system and the VCalendar and return the container
        ///     node with this data.
        /// </summary>
        /// <param name="incomPropNode">
        ///     This node contains the requested data. Is the first prop node
        ///     of the calendar-query.
        /// </param>
        /// <param name="resource">The calendar where to extract the data.</param>
        /// <returns>Return the prop node that contains the requested data</returns>
        private async Task <List <IXMLTreeStructure> > ProccessPropNode(IXMLTreeStructure incomPropNode,
                                                                        KeyValuePair <string, VCalendar> resource)
        {
            var output = new List <IXMLTreeStructure>();

            var resPropertiesOk       = new List <XmlTreeStructure>();
            var resPropertiesNotExist = new List <XmlTreeStructure>();

            var href        = resource.Key[0] != '/' ? "/" + resource.Key : resource.Key;
            var calResource = _resourceRepository.Get(href);

            foreach (var prop in incomPropNode.Children)
            {
                //create an instance of a XMlTreeStrucure with the same name and
                //ns that the requested
                var currentPropNode = new XmlTreeStructure(prop.NodeName, prop.MainNamespace);
                switch (prop.NodeName)
                {
                //if the requested prop is calendar data then take the content of the
                //resource
                case "calendar-data":
                    //see if the calendar-data describes pros to take
                    // if does then take them if not take it all
                    currentPropNode.AddValue(prop.Children.Any()
                            ? resource.Value.ToString(prop)
                            : resource.Value.ToString());
                    resPropertiesOk.Add(currentPropNode);
                    break;

                //if not try to take the property from the resource's properties
                default:
                    var currentProperty = calResource.Properties.FirstOrDefault(p => p.Name == prop.NodeName);
                    currentPropNode.AddValue(currentProperty != null ? currentProperty.PropertyRealValue() : "");
                    if (currentProperty != null)
                    {
                        resPropertiesOk.Add(currentPropNode);
                    }
                    else
                    {
                        resPropertiesNotExist.Add(currentPropNode);
                    }
                    break;
                }
            }

            #region Adding nested propOK

            //This procedure has been explained in another method.
            //Here the retrieve properties are grouped.

            var propstatOK = new XmlTreeStructure("propstat", "DAV:");
            var propOk     = new XmlTreeStructure("prop", "DAV:");

            //Here i add all properties to the prop.
            foreach (var property in resPropertiesOk)
            {
                propOk.AddChild(property);
            }

            propstatOK.AddChild(propOk);

            #endregion

            #region Adding nested status OK

            var statusOK = new XmlTreeStructure("status", "DAV:");
            statusOK.AddValue("HTTP/1.1 200 OK");
            propstatOK.AddChild(statusOK);

            #endregion

            #region Adding nested propWrong

            //Here the properties that could not be retrieved are grouped.
            var propstatWrong = new XmlTreeStructure("propstat", "DAV:");
            var propWrong     = new XmlTreeStructure("prop", "DAV:");

            //Here i add all properties to the prop.
            foreach (var property in resPropertiesNotExist)
            {
                propWrong.AddChild(property);
            }

            propstatWrong.AddChild(propWrong);

            #endregion

            #region Adding nested status Not Found

            var statusWrong = new XmlTreeStructure("status", "DAV:");
            statusWrong.AddValue("HTTP/1.1 400 Not Found");
            propstatWrong.AddChild(statusWrong);

            #endregion

            #region Adding responseDescription when wrong

            //Here i add an description for explain the errors.
            //This should be aplied in all method with an similar structure but for the moment is only used here.
            //However this is not required.
            var responseDescrpWrong = new XmlTreeStructure("responsedescription", "DAV:");
            responseDescrpWrong.AddValue("The properties doesn't  exist");
            propstatWrong.AddChild(responseDescrpWrong);

            #endregion

            if (resPropertiesOk.Any())
            {
                output.Add(propstatOK);
            }
            if (resPropertiesNotExist.Any())
            {
                output.Add(propstatWrong);
            }

            return(output);
        }
Esempio n. 9
0
        /// <summary>
        ///     Having the principal and the requested properties
        ///     then proccess the requestedProperties and build the
        ///     response.
        /// </summary>
        /// <param name="response">The HttpResponse from the controller.</param>
        /// <param name="requestedUrl">The principal url if anyurl </param>
        /// <param name="reqProperties">Contains the requested properties for the principal. key=name, Value = ns</param>
        /// <param name="principal">The instance of the pricipal that is requested</param>
        /// <returns>The final response to return. Has the body with the response and the</returns>
        public async Task BuildResponse(HttpResponse response, string requestedUrl,
                                        List <KeyValuePair <string, string> > reqProperties, Principal principal)
        {
            //if the principal is not authenticated then set in the response statusCode
            if (principal == null)
            {
                response.StatusCode = StatusCodes.Status401Unauthorized;
            }

            var multistatusNode = new XmlTreeStructure("multistatus", "DAV:");

            multistatusNode.Namespaces.Add("D", "DAV:");
            multistatusNode.Namespaces.Add("C", "urn:ietf:params:xml:ns:caldav");
            IEnumerable <IXMLTreeStructure> properties = null;

            //create the response node.
            var responseNode = new XmlTreeStructure("response", "DAV:");

            //create the href node
            var hrefNode = new XmlTreeStructure("href", "DAV:");

            //var url = requestedUrl.Replace(SystemProperties._baseUrl , "");
            hrefNode.AddValue(requestedUrl);

            responseNode.AddChild(hrefNode);

            //in this section is where the "propstat" structure its build.
            var propstatNode = new XmlTreeStructure("propstat", "DAV:");

            var propNode = new XmlTreeStructure("prop", "DAV:");

            //check this because the principal could not be authenticated
            if (principal != null)
            {
                //add the requested properties to the propNode
                //if the properties exist in the principal
                properties = principal.Properties
                             .Where(p => reqProperties.Contains(new KeyValuePair <string, string>(p.Name, p.Namespace)))
                             .Select(x => XmlTreeStructure.Parse(x.Value));
            }

            //check the properties that are generated per request
            //and are not contained in the principal's properties
            foreach (var reqProperty in reqProperties)
            {
                //here the additional properties for the principal that
                //are created per request
                switch (reqProperty.Key)
                {
                case "current-user-principal":
                    propNode.AddChild(PropertyCreation.CreateCurrentUserPrincipal(principal));
                    break;

                case "principal-URL":
                    propNode.AddChild(new XmlTreeStructure("principal-URL", "DAV:")
                    {
                        Value = principal.PrincipalURL
                    });
                    break;
                }
            }

            if (properties != null)
            {
                //add the properties to the propNode
                foreach (var property in properties)
                {
                    propNode.AddChild(property);
                }
            }

            var statusNode = new XmlTreeStructure("status", "DAV:")
            {
                Value = "HTTP/1.1 200 OK"
            };

            //add the propNOde and the status node to the propStatNode
            propstatNode.AddChild(propNode).AddChild(statusNode);

            responseNode.AddChild(propstatNode);

            multistatusNode.AddChild(responseNode);

            //here the multistatus xml for the body is built
            //have to write it to the response body.

            var responseText  = multistatusNode.ToString();
            var responseBytes = Encoding.UTF8.GetBytes(responseText);

            response.ContentLength = responseBytes.Length;
            await response.Body.WriteAsync(responseBytes, 0, responseBytes.Length);
        }
Esempio n. 10
0
        //TODO:Nacho
        public async Task PropPatch(Dictionary <string, string> propertiesAndHeaders, string body, HttpResponse response)
        {
            #region Docummentation

            //Proppatch is the method used by WebDAV for update, create and delete properties.

            //The body structure of a Proppatch request is declare as a "proppertyupdate" xml.

            //As a child of the "proppertyupdate" there are list of "set" and "remove" indicating the
            //operations that have to be process. This element have to be process in order (top to bottom).

            //There has to be at least one expected element inside "proppertyupdate".

            //Each "set" element is composed by a "prop" element witch contains the property name and value
            //of the properties that have to created or updated (if exists or not).

            //The same happens for the "remove" elements but these don't include the value of the property inside
            //the "prop" element.

            #endregion

            #region Extracting Properties

            string calendarResourceId;
            propertiesAndHeaders.TryGetValue("calendarResourceID", out calendarResourceId);

            string url;
            propertiesAndHeaders.TryGetValue("url", out url);

            #endregion

            //Checking precondition
            PreconditionCheck = new ProppatchPrecondition(_collectionRespository, _resourceRespository);
            if (!await PreconditionCheck.PreconditionsOK(propertiesAndHeaders, response))
            {
                return;
            }

            //Creating and filling the root of the xml tree response
            //All response of a request is conformed by a "multistatus" element.
            var multistatus = new XmlTreeStructure("multistatus", "DAV:");
            multistatus.Namespaces.Add("D", "DAV:");
            multistatus.Namespaces.Add("C", "urn:ietf:params:xml:ns:caldav");

            response.ContentType = "application/xml";

            //getting the request body structure
            IXMLTreeStructure xmlTree;
            try
            {
                xmlTree = XmlTreeStructure.Parse(body);
            }
            catch (Exception)
            {
                response.StatusCode = StatusCodes.Status400BadRequest;
                return;
            }


            //checking that the request has propertyupdate node

            if (xmlTree.NodeName != "propertyupdate")
            {
                response.StatusCode = (int)HttpStatusCode.BadRequest;
                await
                response.WriteAsync(
                    @"Body in bad format, body of proppatch must contain ""propertyupdate"" xml element");

                return;
            }

            //throw new ArgumentException(@"Body in bad format, body of proppatch must contain ""propertyupdate"" xml element");

            var propertyupdate = xmlTree;
            //aliasing the list with all "set" and "remove" structures inside "propertyupdate".
            var setsAndRemoves = propertyupdate.Children;

            //propertyupdate must have at least one element
            if (setsAndRemoves.Count == 0)
            {
                response.StatusCode = (int)HttpStatusCode.BadRequest;
                await response.WriteAsync("propertyupdate must have at least one element");

                return;
                //throw new ArgumentException("propertyupdate must have at least one element");
            }


            //The structure of a response for a proppatch has a "multistatus"
            //as root inside it, there is only one response because depth is not allowed.
            //Inside the "response" is necessary to add a "propstat" for each property.
            //This "propstat" is built with a "prop" element containing just the property name
            //and a "status" with the exit status code.
            var responseTree = new XmlTreeStructure("response", "DAV:");
            multistatus.AddChild(responseTree);

            #region Adding the <D:href>/api/v1/collections/{userEmail}|{groupName}/{principalId}/{collectionName}/{calendarResourceId}?</D:href>

            var href = new XmlTreeStructure("href", "DAV:");

            href.AddValue(SystemProperties._baseUrl + url);


            responseTree.AddChild(href);

            #endregion

            //Proppatch is atomic, though when an error occurred in one property,
            //all failed, an all other properties received a "424 failed dependency".
            var hasError = false;

            //Here it is garanted that if an error occured during the processing of the operations
            //The changes will not be stored in db thanks to a rollback.


            //For each set and remove try to execute the operation if something fails
            //put the Failed Dependency Error to every property before and after the error
            //even if the operation for the property was succesfully changed.
            foreach (var setOrRemove in setsAndRemoves)
            {
                if (setOrRemove.NodeName == "set")
                {
                    hasError = await BuiltResponseForSet(url, calendarResourceId, hasError,
                                                         setOrRemove, responseTree);
                }
                else
                {
                    hasError = await BuiltResponseForRemove(url, calendarResourceId, hasError,
                                                            setOrRemove, responseTree);
                }
            }

            if (hasError)
            {
                ChangeToDependencyError(responseTree);
            }
            else
            {
                await _collectionRespository.SaveChangeAsync();
            }

            response.StatusCode = 207;
            await response.WriteAsync(multistatus.ToString());
        }
Esempio n. 11
0
        public async Task MkCalendar(Dictionary <string, string> propertiesAndHeaders, string body, HttpResponse response)
        {
            #region Extracting Properties

            string principalId;
            propertiesAndHeaders.TryGetValue("principalId", out principalId);

            string url;
            propertiesAndHeaders.TryGetValue("url", out url);

            #endregion

            propertiesAndHeaders.Add("body", body);

            PreconditionCheck = new MKCalendarPrecondition(StorageManagement, _collectionRespository);
            PosconditionCheck = new MKCalendarPosCondition(StorageManagement, _collectionRespository);

            //Checking that all precondition pass

            //Cheking Preconditions
            if (!await PreconditionCheck.PreconditionsOK(propertiesAndHeaders, response))
            {
                return;
            }

            //I create here the collection already but i wait for other comprobations before save the database.
            await CreateDefaultCalendar(propertiesAndHeaders);

            response.StatusCode = (int)HttpStatusCode.Created;


            //If it has not body and  Posconditions are OK, it is created with default values.
            if (string.IsNullOrEmpty(body))
            {
                if (!await PosconditionCheck.PosconditionOk(propertiesAndHeaders, response))
                {
                    await DeleteCalendarCollection(propertiesAndHeaders, response);

                    response.StatusCode = (int)HttpStatusCode.Forbidden;
                    await response.WriteAsync("Poscondition Failed");

                    return;
                }
                await _collectionRespository.SaveChangeAsync();

                return;
            }

            //If a body exist the it is parsed like an XmlTree
            var mkCalendarTree = XmlTreeStructure.Parse(body);

            //if it does not have set property it is treated as a empty body.
            if (mkCalendarTree.Children.Count == 0)
            {
                if (!await PosconditionCheck.PosconditionOk(propertiesAndHeaders, response))
                {
                    await DeleteCalendarCollection(propertiesAndHeaders, response);

                    response.StatusCode = (int)HttpStatusCode.Forbidden;
                    await response.WriteAsync("Poscondition Failed");

                    return;
                }
                await _collectionRespository.SaveChangeAsync();

                return;
            }

            //now it is assumed that the body contains a set
            var setTree = mkCalendarTree.GetChild("set");

            #region Response Construction in case of error

            //this only if error during processing.
            //Creating and filling the root of the xml tree response
            //All response of a request is conformed by a "multistatus" element.
            var multistatus = new XmlTreeStructure("multistatus", "DAV:");
            multistatus.Namespaces.Add("D", "DAV:");
            multistatus.Namespaces.Add("C", "urn:ietf:params:xml:ns:caldav");

            var responseTree = new XmlTreeStructure("response", "DAV:");
            multistatus.AddChild(responseTree);

            var href = new XmlTreeStructure("href", "DAV:");
            href.AddValue(SystemProperties._baseUrl + url);

            #endregion

            //Check if any error occurred during body processing.
            var hasError = await BuiltResponseForSet(url, null, false, setTree, responseTree);

            if (hasError)
            {
                await DeleteCalendarCollection(propertiesAndHeaders, response);

                response.ContentType = "application/xml";

                ChangeToDependencyError(responseTree);

                response.StatusCode = 207;
                await response.WriteAsync(multistatus.ToString());

                return;
            }

            //Checking Preconditions
            if (await PosconditionCheck.PosconditionOk(propertiesAndHeaders, response))
            {
                await _collectionRespository.SaveChangeAsync();

                return;
                // return createdMessage;
            }

            await DeleteCalendarCollection(propertiesAndHeaders, response);

            response.StatusCode = (int)HttpStatusCode.Forbidden;
            await response.WriteAsync("Poscondition Failed");
        }