//--- Class Methods ---
 private static void XmlRpcLiteralRecurse(XDoc xdoc, DekiScriptLiteral value, bool isArgumentList) {
     if(!isArgumentList) {
         xdoc.Start("value");
     }
     switch(value.ScriptType) {
     case DekiScriptType.BOOL:
         xdoc.Elem("boolean", ((DekiScriptBool)value).Value ? "1" : "0");
         break;
     case DekiScriptType.NUM:
         xdoc.Elem("double", ((DekiScriptNumber)value).Value);
         break;
     case DekiScriptType.STR:
         xdoc.Elem("string", ((DekiScriptString)value).Value); // in order to work with php, this may need to be encoded
         break;
     case DekiScriptType.NIL:
         xdoc.Elem("nil");
         break;
     case DekiScriptType.URI:
         xdoc.Start("string").Attr("type", "uri").End();
         break;
     case DekiScriptType.XML:
         xdoc.Start("string").Attr("type", "xml").Value(value.NativeValue.ToString()).End();
         break;
     case DekiScriptType.LIST:
         xdoc.Start(isArgumentList ? "params" : "array");
         if(!isArgumentList)
             xdoc.Start("data");
         foreach(DekiScriptLiteral entry in ((DekiScriptList)value).Value) {
             if(isArgumentList) {
                 xdoc.Start("param");
                 XmlRpcLiteralRecurse(xdoc, entry, false);
                 xdoc.End();
             } else {
                 XmlRpcLiteralRecurse(xdoc, entry, false);
             }
         }
         if(!isArgumentList)
             xdoc.End();
         xdoc.End();
         break;
     case DekiScriptType.MAP:
         xdoc.Start("struct");
         foreach(KeyValuePair<string, DekiScriptLiteral> entry in ((DekiScriptMap)value).Value) {
             xdoc.Start("member");
             xdoc.Elem("name", entry.Key);
             XmlRpcLiteralRecurse(xdoc, entry.Value, false);
             xdoc.End();
         }
         xdoc.End();
         break;
     default:
         throw new ShouldNeverHappenException("unkwown type");
     }
     if(!isArgumentList)
         xdoc.End();
     return;
 }
Esempio n. 2
0
 private static XDoc EnsureElement(XDoc doc, string parentKey, string key, string def) {
     XDoc parent = doc[parentKey];
     if (parent.IsEmpty) {
         doc.Start(parentKey);
         if (key == null)
             doc.Value(def);
         doc.End();
         parent = doc[parentKey];
     }
     if (key == null)
         return parent;
     XDoc child = parent[key];
     if (child.IsEmpty) {
         if (def == null) {
             child = null;
         } else {
             parent.Start(key);
             parent.Value(def);
             parent.End();
             child = parent[key];
         }
     } else if (def == null && child.Contents == "") {
         child.Remove();
         child = null;
     }
     return child;
 }
 public XDoc Link(
     [DekiExtParam("bug id")] int id
 ) {
     IssueData bug = _service.mc_issue_get(_username, _password, id.ToString());
     XDoc result = new XDoc("html");
     result.Start("body");
     BuildBugLink(bug, result);
     result.End();
     return result;
 }
Esempio n. 4
0
 public XDoc Link(
     [DekiExtParam("bug id")] int id
 ) {
     object[] ticket = _trac.TicketGet(id);
     
     XDoc result = new XDoc("html");
     result.Start("body");
     BuildBugLink((XmlRpcStruct) ticket[3], result, id);
     result.End();
     return result;
 }
Esempio n. 5
0
 public void LogSpaceConversion(XDoc spaceManifest, string space, string confUrl, string mtPath) {
     string xpath = string.Format("space[@space='{0}']", space);
     XDoc spaceXml = spaceManifest[xpath];
     
     if(spaceXml.IsEmpty) {
         spaceManifest.Start("url");
         spaceManifest.Attr("space", space);
         spaceManifest.Attr("c.path", Utils.GetUrlLocalUri(_confBaseUrl, confUrl, false, false));
         spaceManifest.Attr("mt.path", mtPath);
         spaceManifest.End();
     }
 }
Esempio n. 6
0
        public void LogCommentConversion(XDoc spaceManifest, string space, RemoteComment comment, string mtPath) {
            string xpath = string.Format("comment[@c.commentid='{0}']", comment.id);
            XDoc commentXml = spaceManifest[xpath];

            if(commentXml.IsEmpty) {
                spaceManifest.Start("comment");
                spaceManifest.Attr("c.space", space);
                spaceManifest.Attr("c.commentid", comment.id);
                spaceManifest.Attr("c.pageid", comment.pageId);
                spaceManifest.Attr("c.path", Utils.GetUrlLocalUri(_confBaseUrl, comment.url, true, false));
                spaceManifest.Attr("mt.path", mtPath);
                spaceManifest.End();
            }
        }
Esempio n. 7
0
        public void LogFileConversion(XDoc spaceManifest, RemoteAttachment fileInfo, string contentUrl) {
            string xpath = string.Format("file[@c.fileid='{0}']", fileInfo.id);

            XDoc fileXml = spaceManifest[xpath];
            if(fileXml.IsEmpty) {
                spaceManifest.Start("file");
                spaceManifest.Attr("c.fileid", fileInfo.id);
                spaceManifest.Attr("c.pageid", fileInfo.pageId);
                spaceManifest.Attr("c.filename", fileInfo.fileName);
                spaceManifest.Attr("c.filesize", fileInfo.fileSize);
                spaceManifest.Attr("c.mimetype", fileInfo.contentType);
                spaceManifest.Attr("c.path", Utils.GetUrlLocalUri(_confBaseUrl, fileInfo.url, false, true));
                spaceManifest.Attr("mt.path", Utils.GetApiUrl(Utils.GetUrlLocalUri(_confBaseUrl, contentUrl, true, true)));
                spaceManifest.End();
            }
        }
Esempio n. 8
0
        public void LogPageConversion(XDoc spaceManifest, ACConverterPageInfo pageInfo) {
            string xpath = string.Format("page[@c.pageid='{0}']", pageInfo.ConfluencePage.id);
            XDoc pageXml = spaceManifest[xpath];

            if(pageXml.IsEmpty) {
                spaceManifest.Start("page");
                spaceManifest.Attr("c.space", pageInfo.ConfluencePage.space);
                spaceManifest.Attr("c.pageid", pageInfo.ConfluencePage.id);
                spaceManifest.Attr("c.parentpageid", pageInfo.ConfluencePage.parentId);
                spaceManifest.Attr("c.path", Utils.GetUrlLocalUri(_confBaseUrl, pageInfo.ConfluencePage.url, true, false));
                spaceManifest.Attr("c.tinyurl", pageInfo.TinyUrl);
                spaceManifest.Attr("mt.pageid", pageInfo.DekiPageId);
                spaceManifest.Attr("mt.path", pageInfo.DekiPageUrl);
                spaceManifest.Attr("title", pageInfo.PageTitle);
                spaceManifest.End();
            }
        }
 public static XDoc WebImage(
     [DekiScriptParam("image uri")] string uri,
     [DekiScriptParam("image width", true)] float? width,
     [DekiScriptParam("image height", true)] float? height,
     [DekiScriptParam("image alternative text", true)] string text
 ) {
     XDoc result = new XDoc("html").Start("body");
     if(uri.EndsWithInvariantIgnoreCase(".svg")) {
         result.Start("iframe").Attr("marginwidth", "0").Attr("marginheight", "0").Attr("hspace", "0").Attr("vspace", "0").Attr("frameborder", "0").Attr("scrolling", "no");
     } else {
         result.Start("img");
     }
     result.Attr("src", WebCheckUri(uri));
     result.Attr("width", WebSize(width));
     result.Attr("height", WebSize(height));
     result.Attr("alt", text);
     result.Attr("title", text);
     result.End();
     result.End();
     return result;
 }
Esempio n. 10
0
        public Yield Table(
            [DekiExtParam("name of Dapp to invoke")] string name,
            [DekiExtParam("xpath for collecting values (default: all groups in Dapp)", true)] string xpath,
            [DekiExtParam("input uri (default: as defined by the Dapp)", true)] XUri input,
            [DekiExtParam("dapp arguments (default: none)", true)] Hashtable args,
            Result <XDoc> response
            )
        {
            Result <XDoc> res;

            yield return(res = Coroutine.Invoke(FetchResult, name, input, args, new Result <XDoc>()));

            XDoc doc = res.Value;

            // fetch value from document
            XDoc result = new XDoc("html")
                          .Start("head")
                          .Start("script").Attr("type", "text/javascript").Attr("src", Files.At("sorttable.js")).End()
                          .Start("style").Attr("type", "text/css").Value(@".feedtable {
    border:1px solid #999;
    line-height:1.5em;
    overflow:hidden;
    width:100%;
}
.feedtable th {
    background-color:#ddd;
    border-bottom:1px solid #999;
    font-size:14px;
}
.feedtable tr {
    background-color:#FFFFFF;
}
.feedtable tr.feedroweven td {
    background-color:#ededed;
}").End()
                          .End()
                          .Start("body");

            result.Start("table").Attr("border", 0).Attr("cellpadding", 0).Attr("cellspacing", 0).Attr("class", "feedtable sortable");
            XDoc rows = doc[xpath ?? ".//*[@type='group']"];

            // create header row
            result.Start("thead").Start("tr");
            foreach (XDoc cell in rows.Elements)
            {
                result.Start("th").Elem("strong", cell.Name).End();
            }
            result.End().End();

            // create data rows
            int rowcount = 0;

            result.Start("tbody");
            foreach (XDoc row in rows)
            {
                result.Start("tr");
                result.Attr("class", ((rowcount++ & 1) == 0) ? "feedroweven" : "feedrowodd");
                foreach (XDoc cell in row.Elements)
                {
                    result.Elem("td", ConvertDocToValue(cell, true));
                }
                result.End();
            }
            result.End();

            // close table & body tags
            result.End().End();
            response.Return(result);
            yield break;
        }
Esempio n. 11
0
        private static XDoc QueryPageVersions(ulong pageId, int? afterRevision, int? beforeRevision, IDictionary<string, XDoc> cache) {
            XDoc doc = new XDoc("diff");

            // retrieve 'after' version
            if(afterRevision.HasValue) {
                XDoc contents;
                string key = string.Format("{0}-{1}", pageId, afterRevision);

                // chek if we have a cached version
                if(!cache.TryGetValue(key, out contents)) {

                    // store response (doesn't matter if it was successful or not)
                    cache[key] = contents = GetParsedPageRevision(pageId, afterRevision.Value);
                }
                if(contents != null) {
                    doc.Start("after").Start("body");
                    doc.Elem("h1", contents["@title"].AsText);
                    doc.AddNodes(contents["body"]);
                    doc.End().End();
                }
            }

            // check if 'before' version is expected to be different
            if(beforeRevision.HasValue && (afterRevision != beforeRevision) && (beforeRevision > 0)) {
                XDoc contents;
                string key = string.Format("{0}-{1}", pageId, beforeRevision);

                // chek if we have a cached version
                if(!cache.TryGetValue(key, out contents)) {

                    // store response (doesn't matter if it was successful or not)
                    cache[key] = contents = GetParsedPageRevision(pageId, beforeRevision.Value);
                }
                if(contents != null) {
                    doc.Start("before").Start("body");
                    doc.Elem("h1", contents["@title"].AsText);
                    doc.AddNodes(contents["body"]);
                    doc.End().End();
                }
            }
            return doc;
        }
Esempio n. 12
0
        //--- Methods ---
        private XDoc BuildBugLink(XmlRpcStruct bug, XDoc doc, int bugid) {
            string status = bug["status"].ToString();
            string reporter = bug["reporter"].ToString();

            // The severity-param is not submitted by trac if no severity-entry is defined
            string severity = string.Empty;
            if(bug["severity"] != null) {
                severity = bug["severity"].ToString();
            }

            string owner = bug["owner"].ToString();
            string summary = bug["summary"].ToString();

            bool strikeThrough = !string.IsNullOrEmpty(status) && Array.Exists<string>(STRIKE_THROUGH_STATUSES, delegate(string s) {
                return StringUtil.EqualsInvariantIgnoreCase(status.ToLowerInvariant(), s);
            });

            string title = string.Format("{0} (Reporter: {1} Owner: {2})",
                summary,
                reporter,
                owner);

            doc.Start("a").Attr("href", _uri.At("ticket", bugid.ToString())).Attr("title", title);
            if (strikeThrough) {
                doc.Start("del").Value(bugid).End();
            } else {
                doc.Value(bugid);
            }
            doc.End();
            return doc;
        }
Esempio n. 13
0
 private static void WriteXSpan(XmlNode node, XDoc output)
 {
     switch(node.NodeType) {
     case XmlNodeType.Document:
         WriteXSpan(((XmlDocument)node).DocumentElement, output);
         break;
     case XmlNodeType.Element:
         XDoc childOutput = output.Start("span");
         childOutput.Attr("class", node.Name);
         foreach(XmlNode attr in node.Attributes) {
             output.Attr("xml:" + attr.Name, attr.Value);
         }
         foreach(XmlNode child in node.ChildNodes) {
             WriteXSpan(child, output);
         }
         output.End();
         break;
     case XmlNodeType.Text:
         output.Value(node.Value);
         break;
     }
 }
        //--- Class Methods ---

        /// <summary>
        /// Create a service blueprint from reflection and attribute meta-data for an <see cref="IDreamService"/> implementation.
        /// </summary>
        /// <param name="type">Type of examine.</param>
        /// <returns>Xml formatted blueprint.</returns>
        public static XDoc CreateServiceBlueprint(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            XDoc result = new XDoc("blueprint");

            // load assembly
            Dictionary <string, string> assemblySettings = new Dictionary <string, string>(StringComparer.Ordinal);

            string[] assemblyParts = type.Assembly.FullName.Split(',');
            foreach (string parts in assemblyParts)
            {
                string[] assign = parts.Trim().Split(new char[] { '=' }, 2);
                if (assign.Length == 2)
                {
                    assemblySettings[assign[0].Trim()] = assign[1].Trim();
                }
            }
            result.Start("assembly");
            foreach (KeyValuePair <string, string> entry in assemblySettings)
            {
                result.Attr(entry.Key, entry.Value);
            }
            result.Value(assemblyParts[0]);
            result.End();
            result.Elem("class", type.FullName);

            // retrieve DreamService attribute on class definition
            DreamServiceAttribute serviceAttrib = (DreamServiceAttribute)Attribute.GetCustomAttribute(type, typeof(DreamServiceAttribute), false);

            result.Elem("name", serviceAttrib.Name);
            result.Elem("copyright", serviceAttrib.Copyright);
            result.Elem("info", serviceAttrib.Info);

            // retrieve DreamServiceUID attributes
            foreach (XUri sid in serviceAttrib.GetSIDAsUris())
            {
                result.Elem("sid", sid);
            }

            // check if service has blueprint settings
            foreach (DreamServiceBlueprintAttribute blueprintAttrib in Attribute.GetCustomAttributes(type, typeof(DreamServiceBlueprintAttribute), true))
            {
                result.InsertValueAt(blueprintAttrib.Name, blueprintAttrib.Value);
            }

            // check if service has configuration information
            DreamServiceConfigAttribute[] configAttributes = (DreamServiceConfigAttribute[])Attribute.GetCustomAttributes(type, typeof(DreamServiceConfigAttribute), true);
            if (!ArrayUtil.IsNullOrEmpty(configAttributes))
            {
                result.Start("configuration");
                foreach (DreamServiceConfigAttribute configAttr in configAttributes)
                {
                    result.Start("entry")
                    .Elem("name", configAttr.Name)
                    .Elem("valuetype", configAttr.ValueType)
                    .Elem("description", configAttr.Description)
                    .End();
                }
                result.End();
            }

            // retrieve DreamFeature attributes on method definitions
            result.Start("features");
            MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            foreach (MethodInfo method in methods)
            {
                // retrieve feature description
                Attribute[] featureAttributes = Attribute.GetCustomAttributes(method, typeof(DreamFeatureAttribute), false);
                if (featureAttributes.Length == 0)
                {
                    continue;
                }
                if (method.IsGenericMethod || method.IsGenericMethodDefinition)
                {
                    throw new NotSupportedException(string.Format("generic methods are not supported ({0})", method.Name));
                }

                // determine access level
                string access;
                if (method.IsPublic)
                {
                    access = "public";
                }
                else if (method.IsAssembly)
                {
                    access = "internal";
                }
                else if (method.IsPrivate || method.IsFamily)
                {
                    access = "private";
                }
                else
                {
                    throw new NotSupportedException(string.Format("access level is not supported ({0})", method.Name));
                }

                // retrieve feature parameter descriptions, filters, prologues, and epilogues
                Attribute[] paramAttributes = Attribute.GetCustomAttributes(method, typeof(DreamFeatureParamAttribute), false);
                var         pathAttributes  = method.GetParameters().Select(p => {
                    var attr = (PathAttribute)p.GetCustomAttributes(typeof(PathAttribute), false).FirstOrDefault();
                    return(((attr != null) && (attr.Name == null)) ? new PathAttribute {
                        Description = attr.Description, Name = p.Name
                    } : attr);
                }).Where(p => p != null);
                var queryAttributes = method.GetParameters().Select(q => {
                    var attr = (QueryAttribute)q.GetCustomAttributes(typeof(QueryAttribute), false).FirstOrDefault();
                    return(((attr != null) && (attr.Name == null)) ? new QueryAttribute {
                        Description = attr.Description, Name = q.Name
                    } : attr);
                }).Where(q => q != null);
                Attribute[] statusAttributes = Attribute.GetCustomAttributes(method, typeof(DreamFeatureStatusAttribute), false);
                foreach (DreamFeatureAttribute featureAttrib in featureAttributes)
                {
                    result.Start("feature");
                    result.Elem("obsolete", featureAttrib.Obsolete);
                    result.Elem("pattern", featureAttrib.Pattern);
                    result.Elem("description", featureAttrib.Description);
                    string info = featureAttrib.Info ?? serviceAttrib.Info;
                    if (info != null)
                    {
                        result.Elem("info", info);
                    }
                    result.Elem("method", method.Name);

                    // add parameter descriptions (as seen on the method definition)
                    foreach (DreamFeatureParamAttribute paramAttrib in paramAttributes)
                    {
                        result.Start("param");
                        result.Elem("name", paramAttrib.Name);
                        if (!string.IsNullOrEmpty(paramAttrib.ValueType))
                        {
                            result.Elem("valuetype", paramAttrib.ValueType);
                        }
                        result.Elem("description", paramAttrib.Description);
                        result.End();
                    }

                    // add parameter descriptions (as seen on the method parameters)
                    foreach (PathAttribute pathAttrib in pathAttributes)
                    {
                        result.Start("param")
                        .Elem("name", "{" + pathAttrib.Name + "}")
                        .Elem("description", pathAttrib.Description)
                        .End();
                    }

                    // add parameter descriptions (as seen on the method parameters)
                    foreach (QueryAttribute queryAttrib in queryAttributes)
                    {
                        result.Start("param")
                        .Elem("name", queryAttrib.Name)
                        .Elem("description", queryAttrib.Description)
                        .End();
                    }

                    // add status codes
                    foreach (DreamFeatureStatusAttribute paramAttrib in statusAttributes)
                    {
                        result.Start("status");
                        result.Attr("value", (int)paramAttrib.Status);
                        result.Value(paramAttrib.Description);
                        result.End();
                    }

                    // add access level
                    result.Elem("access", access);
                    result.End();
                }
            }
            result.End();
            return(result.EndAll());
        }
Esempio n. 15
0
        private void ConvertPagePermissions(string tWikiWebDataPath, string exportPagesPath)
        {
            if (_convertedUsers.Count == 0)
            {
                return;
            }

            List<TWikiUser> allowViewWebUsers = new List<TWikiUser>();
            List<TWikiUser> denyViewWebUsers = new List<TWikiUser>();
            List<TWikiUser> allowChangeWebUsers = new List<TWikiUser>();
            List<TWikiUser> denyChangeWebUsers = new List<TWikiUser>();

            List<TWikiGroup> allowViewWebGroups = new List<TWikiGroup>();
            List<TWikiGroup> denyViewWebGroups = new List<TWikiGroup>();
            List<TWikiGroup> allowChangeWebGroups = new List<TWikiGroup>();
            List<TWikiGroup> denyChangeWebGroups = new List<TWikiGroup>();

            bool noWebChangeRestrictions = true;
            bool noWebRestrictions = true;

            bool foundAllowWebChange = false;
            bool foundAllowWebView = false;
            bool foundDenyWebView = false;
            bool foundDenyWebChange = false;

            string WebPrefrencesPagePath = Path.Combine(tWikiWebDataPath, WebPrefrencesPageName);
            if (File.Exists(WebPrefrencesPagePath))
            {
                string webPrefrencesPageContent = File.ReadAllText(WebPrefrencesPagePath);

                string[] allowChangeWebNames = ExtractNamesList(webPrefrencesPageContent, "ALLOWWEBCHANGE", out foundAllowWebChange);

                string[] denyChangeWebNames = ExtractNamesList(webPrefrencesPageContent, "DENYWEBCHANGE", out foundDenyWebChange);

                string[] allowViewWebNames = ExtractNamesList(webPrefrencesPageContent, "ALLOWWEBVIEW", out foundAllowWebView);
                
                string[] denyViewWebNames = ExtractNamesList(webPrefrencesPageContent, "DENYWEBVIEW", out foundDenyWebView);

                noWebChangeRestrictions = (allowChangeWebNames.Length == 0)
                                  && (denyChangeWebNames.Length == 0);

                noWebRestrictions = noWebChangeRestrictions
                                        && (allowViewWebNames.Length == 0)
                                        && (denyViewWebNames.Length == 0);

                foreach (string name in allowChangeWebNames)
                {
                    TWikiUser user = null;
                    if (_convertedUsers.TryGetValue(name, out user))
                    {
                        allowChangeWebUsers.Add(user);
                    }
                    TWikiGroup group = null;
                    if (_convertedGroups.TryGetValue(name, out group))
                    {
                        allowChangeWebGroups.Add(group);
                    }
                }

                foreach (string name in denyChangeWebNames)
                {
                    TWikiUser user = null;
                    if (_convertedUsers.TryGetValue(name, out user))
                    {
                        denyChangeWebUsers.Add(user);
                    }
                    TWikiGroup group = null;
                    if (_convertedGroups.TryGetValue(name, out group))
                    {
                        denyChangeWebGroups.Add(group);
                    }
                }

                foreach (string name in allowViewWebNames)
                {
                    TWikiUser user = null;
                    if (_convertedUsers.TryGetValue(name, out user))
                    {
                        allowViewWebUsers.Add(user);
                    }
                    TWikiGroup group = null;
                    if (_convertedGroups.TryGetValue(name, out group))
                    {
                        allowViewWebGroups.Add(group);
                    }
                }

                foreach (string name in denyViewWebNames)
                {
                    TWikiUser user = null;
                    if (_convertedUsers.TryGetValue(name, out user))
                    {
                        denyViewWebUsers.Add(user);
                    }
                    TWikiGroup group = null;
                    if (_convertedGroups.TryGetValue(name, out group))
                    {
                        denyViewWebGroups.Add(group);
                    }
                }
            }

            allowChangeWebUsers = AppendUsersList(allowChangeWebUsers, allowChangeWebGroups);
            allowViewWebUsers = AppendUsersList(allowViewWebUsers, allowViewWebGroups);
            denyChangeWebUsers = AppendUsersList(denyChangeWebUsers, denyChangeWebGroups);
            denyViewWebUsers = AppendUsersList(denyViewWebUsers, denyViewWebGroups);

            foreach (string tWikiPageDataFile in Directory.GetFiles(tWikiWebDataPath, "*.txt"))
            {
                if (!(Path.GetExtension(tWikiPageDataFile).TrimStart('.').ToLower() == "txt"))
                {
                    continue;
                }
                string pageName = Path.GetFileNameWithoutExtension(Path.GetFileName(tWikiPageDataFile));
                string pageDekiPath = XUri.DoubleEncodeSegment(exportPagesPath + "/" + pageName);
                string pageText = File.ReadAllText(tWikiPageDataFile);

                bool foundAllowTopicChange = false;
                string[] allowChangeNames = ExtractNamesList(pageText, "ALLOWTOPICCHANGE", out foundAllowTopicChange);

                bool foundDenyTopicChange = false;
                string[] denyChangeNames = ExtractNamesList(pageText, "DENYTOPICCHANGE", out foundDenyTopicChange);

                bool foundAllowTopicView = false;
                string[] allowViewNames = ExtractNamesList(pageText, "ALLOWTOPICVIEW", out foundAllowTopicView);

                bool foundDenyTopicView = false;
                string[] denyViewNames = ExtractNamesList(pageText, "DENYTOPICVIEW", out foundDenyTopicView);

                bool setSemiPublicPermissions = false;

                if ((foundDenyTopicView) && (denyViewNames.Length == 0))
                {
                    //See item 3 of "How TWiki evaluates ALLOW/DENY settings" on TWikiAccessControl page.
                    //This marked as deprecated and may change.
                    continue;
                }

                if (foundDenyTopicChange && (denyChangeNames.Length == 0))
                {
                    //See item 3 of "How TWiki evaluates ALLOW/DENY settings" on TWikiAccessControl page.
                    //This marked as deprecated and may change.
                    continue;
                }

                bool noTopicChangePermisions = (allowChangeNames.Length == 0)
                             && (denyChangeNames.Length == 0);

                bool noTopicRestrictions = noTopicChangePermisions
                                  && (allowViewNames.Length == 0)
                                  && (denyViewNames.Length == 0);

                if (noWebRestrictions && noTopicRestrictions)
                {
                    continue;
                }

                List<TWikiUser> allowViewTopicUsers = new List<TWikiUser>();
                List<TWikiUser> denyViewTopicUsers = new List<TWikiUser>();
                List<TWikiUser> allowChangeTopicUsers = new List<TWikiUser>();
                List<TWikiUser> denyChangeTopicUsers = new List<TWikiUser>();

                List<TWikiGroup> allowViewTopicGroups = new List<TWikiGroup>();
                List<TWikiGroup> denyViewTopicGroups = new List<TWikiGroup>();
                List<TWikiGroup> allowChangeTopicGroups = new List<TWikiGroup>();
                List<TWikiGroup> denyChangeTopicGroups = new List<TWikiGroup>();

                foreach (string name in allowChangeNames)
                {
                    TWikiUser user = null;
                    if (_convertedUsers.TryGetValue(name, out user))
                    {
                        allowChangeTopicUsers.Add(user);
                    }
                    TWikiGroup group = null;
                    if (_convertedGroups.TryGetValue(name, out group))
                    {
                        allowChangeTopicGroups.Add(group);
                    }
                }

                foreach (string name in denyChangeNames)
                {
                    TWikiUser user = null;
                    if (_convertedUsers.TryGetValue(name, out user))
                    {
                        denyChangeTopicUsers.Add(user);
                    }
                    TWikiGroup group = null;
                    if (_convertedGroups.TryGetValue(name, out group))
                    {
                        denyChangeTopicGroups.Add(group);
                    }
                }

                foreach (string name in allowViewNames)
                {
                    TWikiUser user = null;
                    if (_convertedUsers.TryGetValue(name, out user))
                    {
                        allowViewTopicUsers.Add(user);
                    }
                    TWikiGroup group = null;
                    if (_convertedGroups.TryGetValue(name, out group))
                    {
                        allowViewTopicGroups.Add(group);
                    }
                }

                foreach (string name in denyViewNames)
                {
                    TWikiUser user = null;
                    if (_convertedUsers.TryGetValue(name, out user))
                    {
                        denyViewTopicUsers.Add(user);
                    }
                    TWikiGroup group = null;
                    if (_convertedGroups.TryGetValue(name, out group))
                    {
                        denyViewTopicGroups.Add(group);
                    }
                }

                allowViewTopicUsers = AppendUsersList(allowViewTopicUsers, allowViewTopicGroups);
                allowChangeTopicUsers = AppendUsersList(allowChangeTopicUsers, allowChangeTopicGroups);
                denyViewTopicUsers = AppendUsersList(denyViewTopicUsers, denyViewTopicGroups);
                denyChangeTopicUsers = AppendUsersList(denyChangeTopicUsers, denyChangeTopicGroups);

                List<TWikiUser> allowedUserList = new List<TWikiUser>();

                if (foundAllowTopicView && !foundAllowTopicChange)
                {
                    foreach (TWikiUser user in allowViewTopicUsers)
                    {
                        if (!denyViewTopicUsers.Contains(user))
                        {
                            allowedUserList.Add(user);
                        }
                    }
                }

                if (!foundAllowTopicView && foundAllowTopicChange)
                {
                    if (denyViewTopicUsers.Count == 0)
                    {
                        setSemiPublicPermissions = true;
                    }
                    foreach (TWikiUser user in allowChangeTopicUsers)
                    {
                        if ((!denyChangeTopicUsers.Contains(user)) && (!denyViewTopicUsers.Contains(user)))
                        {
                            allowedUserList.Add(user);
                        }
                    }
                }

                if (foundAllowTopicChange && foundAllowTopicView)
                {
                    foreach (TWikiUser user in allowViewTopicUsers)
                    {
                        if (!denyViewTopicUsers.Contains(user))
                        {
                            allowedUserList.Add(user);
                        }
                    }
                    foreach (TWikiUser user in allowChangeTopicUsers)
                    {
                        if ((!denyViewTopicUsers.Contains(user)) && (!denyChangeTopicUsers.Contains(user)))
                        {
                            allowedUserList.Add(user);
                        }
                    }
                }

                if (!foundAllowTopicView && !foundAllowTopicChange)
                {
                    if ((allowViewWebUsers.Count != 0) && (allowChangeWebUsers.Count == 0))
                    {
                        foreach (TWikiUser user in allowViewWebUsers)
                        {
                            if ((!denyViewWebUsers.Contains(user)) && (!denyViewTopicUsers.Contains(user)))
                            {
                                allowedUserList.Add(user);
                            }
                        }
                    }

                    if ((allowViewWebUsers.Count == 0) && (allowChangeWebUsers.Count != 0))
                    {
                        if ((denyViewWebUsers.Count == 0) && (denyViewTopicUsers.Count == 0))
                        {
                            setSemiPublicPermissions = true;
                        }
                        foreach (TWikiUser user in allowChangeWebUsers)
                        {
                            if ((!denyViewWebUsers.Contains(user)) && (!denyChangeWebUsers.Contains(user))
                                && (!denyViewTopicUsers.Contains(user)) && (!denyChangeTopicUsers.Contains(user)))
                            {
                                allowedUserList.Add(user);
                            }
                        }
                    }

                    if ((allowViewWebUsers.Count != 0) && (allowChangeWebUsers.Count != 0))
                    {
                        foreach (TWikiUser user in allowViewWebUsers)
                        {
                            if ((!denyViewWebUsers.Contains(user)) && (!denyViewTopicUsers.Contains(user)))
                            {
                                allowedUserList.Add(user);
                            }
                        }
                        foreach (TWikiUser user in allowChangeWebUsers)
                        {
                            if ((!denyViewWebUsers.Contains(user)) && (!denyChangeWebUsers.Contains(user))
                                && (!denyViewTopicUsers.Contains(user)) && (!denyChangeTopicUsers.Contains(user)))
                            {
                                allowedUserList.Add(user);
                            }
                        }
                    }

                    if ((allowViewWebUsers.Count == 0) && (allowChangeWebUsers.Count == 0))
                    {
                        if ((denyViewTopicUsers.Count == 0) && (denyChangeTopicUsers.Count == 0)
                            && (denyViewWebUsers.Count == 0) && (denyChangeWebUsers.Count == 0))
                        {
                            continue;
                        }
                        if ((denyViewTopicUsers.Count == 0) && (denyViewWebUsers.Count == 0))
                        {
                            setSemiPublicPermissions = true;
                            foreach (TWikiUser user in _convertedUsers.Values)
                            {
                                if ((!denyChangeWebUsers.Contains(user)) && (!denyChangeTopicUsers.Contains(user)))
                                {
                                    allowedUserList.Add(user);
                                }
                            }
                        }
                        else
                        {
                            foreach (TWikiUser user in _convertedUsers.Values)
                            {
                                if ((!denyViewWebUsers.Contains(user)) && (!denyViewTopicUsers.Contains(user)))
                                {
                                    allowedUserList.Add(user);
                                }
                            }
                        }
                    }
                }

                List<TWikiUser> newAllowedUsers = new List<TWikiUser>();
                foreach (TWikiUser user in allowedUserList)
                {
                    if (!newAllowedUsers.Contains(user))
                    {
                        newAllowedUsers.Add(user);
                    }
                }

                if (noWebChangeRestrictions && noTopicChangePermisions)
                {
                    setSemiPublicPermissions = true;
                }

                string dekiRestrictions = "Private";

                if (setSemiPublicPermissions)
                {
                    dekiRestrictions = "Semi-Public";
                }

                XDoc securityDoc = new XDoc("security")
                .Start("permissions.page")
                    .Elem("restriction", dekiRestrictions)
                .End()
                .Start("grants");

                foreach (TWikiUser user in newAllowedUsers)
                {
                    securityDoc
                        .Start("grant")
                        .Start("permissions").Elem("role", "Contributor").End()
                    .Start("user").Attr("id", user.DekiId).End().End();
                }
                securityDoc.End();

                DreamMessage res = _dekiPlug.At("pages", "=" + pageDekiPath, "security").PutAsync(securityDoc).Wait();

                WriteErrorResponse(res, "Error converting page permissions \"" + pageName + "\"");
            }
        }
Esempio n. 16
0
        public virtual Yield GetServiceInfo(DreamContext context, DreamMessage request, Result<DreamMessage> response)
        {
            XDoc blueprint = Blueprint;
            string title = blueprint["name"].AsText ?? "Service Blueprint";
            XDoc result = new XDoc("html").Attr("xmlns", "http://www.w3.org/1999/xhtml")
                .Start("head")
                    .Elem("title", title)
                    .Start("meta").Attr("http-equiv", "content-type").Attr("content", "text/html;charset=utf-8").End()
                    .Start("meta").Attr("http-equiv", "Content-Style-Type").Attr("content", "text/css").End()
                .End();
            if(blueprint.IsEmpty) {
                result.Elem("body", "Missing service blueprint");
            } else {
                result.Start("body")
                        .Elem("h1", title)
                        .Start("p")
                            .Value(blueprint["copyright"].Contents)
                            .Value(" ")
                            .Start("a").Attr("href", blueprint["info"].Contents).Value("(more)").End()
                            .Value(" ")
                            .Start("a").Attr("href", Self.Uri.At("@blueprint").Path).Value("(blueprint)").End()
                        .End();

                // show configuration information
                XDoc config = blueprint["configuration"];
                if(!config.IsEmpty) {
                    result.Elem("h2", "Configuration");
                    result.Start("ul");
                    foreach(XDoc entry in config["entry"]) {
                        result.Start("li");
                        if(entry["valuetype"].Contents != string.Empty) {
                            result.Value(string.Format("{0} = {1} : {2}", entry["name"].Contents, entry["valuetype"].Contents, entry["description"].Contents));
                        } else {
                            result.Value(string.Format("{0} : {1}", entry["name"].Contents, entry["description"].Contents));
                        }
                        result.End();
                    }
                    result.End();
                }

                // sort features by signature then verb
                blueprint["features"].Sort(delegate(XDoc first, XDoc second) {
                    string[] firstPattern = first["pattern"].Contents.Split(new[] { ':' }, 2);
                    string[] secondPattern = second["pattern"].Contents.Split(new[] { ':' }, 2);
                    int cmp = firstPattern[1].CompareInvariantIgnoreCase(secondPattern[1]);
                    if(cmp != 0) {
                        return cmp;
                    }
                    return firstPattern[0].CompareInvariant(secondPattern[0]);
                });

                // display features
                XDoc features = blueprint["features/feature"];
                if(!features.IsEmpty) {
                    result.Elem("h2", "Features");
                    List<string> modifiers = new List<string>();
                    foreach(XDoc feature in features) {
                        modifiers.Clear();

                        // add modifiers
                        string modifier = feature["access"].AsText;
                        if(modifier != null) {
                            modifiers.Add(modifier);
                        }
                        modifier = feature["obsolete"].AsText;
                        if(modifier != null) {
                            modifiers.Add("OBSOLETE => " + modifier);
                        }
                        if(modifiers.Count > 0) {
                            modifier = " (" + string.Join(", ", modifiers.ToArray()) + ")";
                        } else {
                            modifier = string.Empty;
                        }

                        // check if feature has GET verb and no path parameters
                        string pattern = feature["pattern"].Contents;
                        if(pattern.StartsWithInvariantIgnoreCase(Verb.GET + ":") && (pattern.IndexOfAny(new[] { '{', '*', '?' }) == -1)) {
                            string[] parts = pattern.Split(new[] { ':' }, 2);
                            result.Start("h3")
                                .Start("a").Attr("href", context.AsPublicUri(Self.Uri.AtPath(parts[1])))
                                    .Value(feature["pattern"].Contents)
                                .End()
                                .Value(modifier)
                            .End();
                        } else {
                            result.Elem("h3", feature["pattern"].Contents + modifier);
                        }
                        result.Start("p")
                                .Value(feature["description"].Contents)
                                .Value(" ")
                                .Start("a").Attr("href", feature["info"].Contents).Value("(more)").End();
                        XDoc paramlist = feature["param"];
                        if(!paramlist.IsEmpty) {
                            result.Start("ul");
                            foreach(XDoc param in paramlist) {
                                result.Start("li");
                                if(param["valuetype"].Contents != string.Empty) {
                                    result.Value(string.Format("{0} = {1} : {2}", param["name"].Contents, param["valuetype"].Contents, param["description"].Contents));
                                } else {
                                    result.Value(string.Format("{0} : {1}", param["name"].Contents, param["description"].Contents));
                                }
                                result.End();
                            }
                            result.End();
                        }
                        result.End();
                    }
                }
            }
            response.Return(DreamMessage.Ok(MimeType.HTML, result.ToString()));
            yield break;
        }
Esempio n. 17
0
        private Yield FormatResultSet_Helper(SearchResult searchResultSet, SetDiscriminator discriminator, bool explain, TrackingInfo trackingInfo, Result <XDoc> result)
        {
            _log.Debug("formatting result set");
            var searchDoc = new XDoc("search")
                            .Attr("querycount", searchResultSet.Count)
                            .Attr("ranking", IsAdaptiveSearchEnabled ? "adaptive" : "simple")
                            .Elem("parsedQuery", searchResultSet.ExecutedQuery);
            ulong queryId = 0;

            if (trackingInfo != null)
            {
                queryId = trackingInfo.QueryId.Value;
                searchDoc.Attr("queryid", queryId);

                // TODO (arnec): Keep or remove this? It does expose admin visibility data to non-admins
                if (explain)
                {
                    searchDoc.Start("settings").Start("search")
                    .Elem("rating-promote-boost", _settings.GetValue("search/rating-promote-boost", RATING_PROMOTE_BOOST))
                    .Elem("rating-demote-boost", _settings.GetValue("search/rating-demote-boost", RATING_DEMOTE_BOOST))
                    .Elem("rating-count-threshold", _settings.GetValue("search/rating-count-threshold", RATING_COUNT_THRESHOLD))
                    .Elem("rating-rank-midpoint", _settings.GetValue("search/rating-rank-midpoint", RATING_RANK_MIDPOINT))
                    .Elem("search-popularity-boost", _settings.GetValue("search/search-popularity-boost", SEARCH_POPULARITY_BOOST))
                    .Elem("search-popularity-threshold", _settings.GetValue("search/search-popularity-threshold", SEARCH_POPULARITY_THRESHOLD))
                    .End().End();
                }
            }
            var query = searchResultSet as IEnumerable <SearchResultItem>;

            switch (discriminator.SortField)
            {
            case "title":
                query = OrderBy(query, item => item.Title, discriminator.Ascending);
                break;

            case "modified":
                query = OrderBy(query, item => item.Modified, discriminator.Ascending);
                break;

            default:
                query = OrderBy(query, item => item.Rank, discriminator.Ascending);
                break;
            }
            if (discriminator.Offset > 0)
            {
                query = query.Skip(discriminator.Offset.ToInt());
            }
            if (discriminator.Limit > 0 && discriminator.Limit != uint.MaxValue)
            {
                query = query.Take(discriminator.Limit.ToInt());
            }
            var items = query.ToList();

            yield return(Coroutine.Invoke(PopulateDetail, items, new Result()));

            // position starts at 1 not 0, since 0 is the value used when position isn't tracked
            var position = discriminator.Offset + 1;
            var count    = 0;

            foreach (var item in query)
            {
                if (item.Detail == null)
                {
                    continue;
                }
                try {
                    if (trackingInfo != null)
                    {
                        var detail = item.Detail;

                        // Note (arnec): this assumes that any item in a tracked result has an id.page
                        var trackUri = _apiUri.At("site", "query", queryId.ToString())
                                       .With("pageid", item.Detail["id.page"] ?? "0")
                                       .With("rank", item.Rank.ToString())
                                       .With("type", item.Type.ToString().ToLower());
                        if (discriminator.SortField.EqualsInvariantIgnoreCase("rank"))
                        {
                            trackUri = trackUri.With("position", position.ToString());
                        }
                        var uri       = new XUri(detail["uri"]);
                        var path      = detail["path"];
                        var title     = detail["title"];
                        var pageTitle = title;
                        try {
                            switch (item.Type)
                            {
                            case SearchResultType.User:
                                continue;

                            case SearchResultType.File:
                                trackUri  = trackUri.With("typeid", item.TypeId.ToString());
                                uri       = _apiUri.At("files", item.TypeId.ToString(), Title.AsApiParam(title));
                                pageTitle = detail["title.page"];
                                break;

                            case SearchResultType.Comment:
                                trackUri  = trackUri.With("typeid", item.TypeId.ToString());
                                uri       = new XUri(Utils.AsPublicUiUri(Title.FromUriPath(path))).WithFragment(uri.Fragment);
                                pageTitle = detail["title.page"];
                                break;

                            default:
                                uri = new XUri(Utils.AsPublicUiUri(Title.FromUriPath(path)));
                                break;
                            }
                        } catch (Exception e) {
                            // Note (arnec): not being able to derive the Ui Uri is not enough reason to skip the item
                            _log.Warn("unable to derive UI uri for item", e);
                        }
                        searchDoc.Start("result")
                        .Elem("id", item.TypeId);
                        if (explain)
                        {
                            var rankable = item as RankableSearchResultItem;
                            if (rankable != null)
                            {
                                searchDoc.Start("explain")
                                .Elem("rank.normalized", rankable.Rank)
                                .Elem("rank.raw", rankable.RawRank)
                                .Elem("lucene-score", rankable.LuceneScore)
                                .Elem("lucene-position", rankable.Position)
                                .Elem("normalized-rating", rankable.Rating)
                                .Elem("rating-count", rankable.RatingCount)
                                .Elem("rating-boost", rankable.RatingBoost)
                                .Elem("search-popularity", rankable.SearchPopularity)
                                .Elem("search-popularity-boost", rankable.SearchPopularityBoost)
                                .End();
                            }
                        }
                        searchDoc.Elem("uri", uri)
                        .Elem("uri.track", trackUri)
                        .Elem("rank", item.Rank)
                        .Elem("title", title)
                        .Start("page")
                        .Start("rating").Attr("score", detail["rating.score"]).Attr("count", detail["rating.count"]).End()
                        .Elem("title", pageTitle)
                        .Elem("path", path)
                        .End()
                        .Elem("author", detail["author"])
                        .Elem("date.modified", item.Modified)
                        .Elem("content", detail["preview"])
                        .Elem("type", item.Type.ToString().ToLower())
                        .Elem("mime", detail["mime"])
                        .Elem("tag", detail["tag"])
                        .Elem("size", detail["size"])
                        .Elem("wordcount", detail["wordcount"])
                        .End();
                        position++;
                    }
                    else
                    {
                        searchDoc.Start("document").Elem("score", item.Rank);
                        foreach (var kvp in item.Detail)
                        {
                            if (kvp.Key.EqualsInvariant("score"))
                            {
                                continue;
                            }
                            searchDoc.Elem(kvp.Key, kvp.Value);
                        }
                        searchDoc.End();
                    }
                } catch (Exception e) {
                    // skip any item we cannot process
                    _log.Warn("unable to process search data for item", e);

                    // Note (arnec): skipping an item throws off total and querycount and messes with offset. It's an outlier in the first place
                    // so probably not worth correcting for.
                }
                count++;
            }
            searchDoc.Attr("count", count);
            result.Return(searchDoc);
            yield break;
        }
Esempio n. 18
0
        public void TestPutSiteServiceId() {
            Plug p = Utils.BuildPlugForAdmin();
            XDoc serviceXml = new XDoc("service");
            serviceXml.Elem("sid", TEST_SERVICE_SID);
            serviceXml.Elem("type", "ext");
            serviceXml.Elem("description", "test1");
            serviceXml.Elem("init", "native");
            serviceXml.Start("config");
            serviceXml.Start("value").Attr("key", "keyfoo1").Value("valbar1").End();
            serviceXml.Start("value").Attr("key", "keyfoo2").Value("valbar2").End();
            serviceXml.End();

            //create the service
            DreamMessage msg = p.At("site", "services").PostAsync(serviceXml).Wait();
            Assert.IsTrue(msg.IsSuccessful, "service creation failed");
            uint service_id = msg.ToDocument()["@id"].AsUInt ?? 0;
            Assert.IsTrue(service_id > 0);
            serviceXml = msg.ToDocument();
            Assert.IsTrue(msg.ToDocument()["description"].AsText == "test1");
            Assert.IsTrue(msg.ToDocument()["config/value[@key = 'keyfoo1']"].AsText == "valbar1");
            Assert.IsTrue(msg.ToDocument()["config/value[@key = 'keyfoo2']"].AsText == "valbar2");

            //edit the service
            serviceXml["description"].Remove();
            serviceXml["config/value[@key = 'keyfoo2']"].Remove();
            serviceXml["config/value[@key = 'keyfoo1']"].Remove();
            serviceXml["config"].Start("value").Attr("key", "keyfoo1new").Value("valbar1new").End();
            serviceXml["config"].Start("value").Attr("key", "keyfoo2new").Value("valbar2new").End();
            serviceXml.Elem("description", "test2");
            msg = p.At("site", "services", service_id.ToString()).PutAsync(serviceXml).Wait();
            Assert.IsTrue(msg.IsSuccessful, "service editing failed");

            //validate edit
            msg = p.At("site", "services", service_id.ToString()).GetAsync().Wait();
            Assert.IsTrue(msg.IsSuccessful);
            Assert.IsTrue(msg.ToDocument()["description"].AsText == "test2");
            Assert.IsTrue(msg.ToDocument()["config/value[@key = 'keyfoo1new']"].AsText == "valbar1new");
            Assert.IsTrue(msg.ToDocument()["config/value[@key = 'keyfoo2new']"].AsText == "valbar2new");
            Assert.IsTrue(msg.ToDocument()["config/value[@key = 'keyfoo1']"].AsText == null);
            Assert.IsTrue(msg.ToDocument()["config/value[@key = 'keyfoo2']"].AsText == null);

            //delete the service
            msg = p.At("site", "services", service_id.ToString()).DeleteAsync().Wait();
            Assert.IsTrue(msg.IsSuccessful, "service deletion failed");
            msg = p.At("site", "services", service_id.ToString()).GetAsync().Wait();
            Assert.IsTrue(msg.Status == DreamStatus.NotFound, "service still exists after deletion");
        }
Esempio n. 19
0
        public Yield GetNavigationSiblings(DreamContext context, DreamMessage request, Result<DreamMessage> response) {
            CheckResponseCache(context, false);

            PageBE page = PageBL_GetPageFromUrl(context, false);
            if (page.Title.IsTalk) {
                page = PageBL.GetPageByTitle(page.Title.AsFront());
            }

            // build response
            IList<NavBE> list = NavBL.QueryNavSiblingsData(page, context.Culture);
            if(ShowDebug(context)) {
                response.Return(DreamMessage.Ok(NavBL.ConvertNavPageListToDoc(list)));
            } else {
                XDoc doc = NavBL.ComputeNavigationDocument(list, page, (uint)page.ID, 0, true, context.GetParam("width", int.MaxValue));
                if(ShowXml(context)) {
                    response.Return(DreamMessage.Ok(doc));
                } else {
                    XDoc result = new XDoc("tree");
                    result.Start("siblings");

                    // add name of sibling nodes
                    System.Text.StringBuilder nodes = new System.Text.StringBuilder();
                    ulong homepageId = DekiContext.Current.Instance.HomePageId;
                    foreach(NavBE sibling in list) {
                        if((sibling.ParentId == page.ParentID) && (sibling.Id != homepageId)) {
                            if(nodes.Length != 0) {
                                nodes.Append(",");
                            }
                            nodes.AppendFormat("n{0}", sibling.Id);
                        }
                    }
                    result.Elem("nodes", nodes.ToString());

                    // add sibling nodes
                    result.Start("html");
                    result.Elem("pre", doc["siblings-pre"].Contents);
                    result.Elem("post", doc["siblings-post"].Contents);
                    result.End();
                    result.End();
                    response.Return(DreamMessage.Ok(result));
                }
            }
            yield break;
        }
Esempio n. 20
0
        //--- Class Methods ---
        /// <summary>
        /// Create a service blueprint from reflection and attribute meta-data for an <see cref="IDreamService"/> implementation.
        /// </summary>
        /// <param name="type">Type of examine.</param>
        /// <returns>Xml formatted blueprint.</returns>
        public static XDoc CreateServiceBlueprint(Type type)
        {
            if(type == null) {
                throw new ArgumentNullException("type");
            }
            XDoc result = new XDoc("blueprint");

            // load assembly
            Dictionary<string, string> assemblySettings = new Dictionary<string, string>(StringComparer.Ordinal);
            string[] assemblyParts = type.Assembly.FullName.Split(',');
            foreach(string parts in assemblyParts) {
                string[] assign = parts.Trim().Split(new char[] { '=' }, 2);
                if(assign.Length == 2) {
                    assemblySettings[assign[0].Trim()] = assign[1].Trim();
                }
            }
            result.Start("assembly");
            foreach(KeyValuePair<string, string> entry in assemblySettings) {
                result.Attr(entry.Key, entry.Value);
            }
            result.Value(assemblyParts[0]);
            result.End();
            result.Elem("class", type.FullName);

            // retrieve DreamService attribute on class definition
            DreamServiceAttribute serviceAttrib = (DreamServiceAttribute)Attribute.GetCustomAttribute(type, typeof(DreamServiceAttribute), false);
            result.Elem("name", serviceAttrib.Name);
            result.Elem("copyright", serviceAttrib.Copyright);
            result.Elem("info", serviceAttrib.Info);

            // retrieve DreamServiceUID attributes
            foreach(XUri sid in serviceAttrib.GetSIDAsUris()) {
                result.Elem("sid", sid);
            }

            // check if service has blueprint settings
            foreach(DreamServiceBlueprintAttribute blueprintAttrib in Attribute.GetCustomAttributes(type, typeof(DreamServiceBlueprintAttribute), true)) {
                result.InsertValueAt(blueprintAttrib.Name, blueprintAttrib.Value);
            }

            // check if service has configuration information
            DreamServiceConfigAttribute[] configAttributes = (DreamServiceConfigAttribute[])Attribute.GetCustomAttributes(type, typeof(DreamServiceConfigAttribute), true);
            if(!ArrayUtil.IsNullOrEmpty(configAttributes)) {
                result.Start("configuration");
                foreach(DreamServiceConfigAttribute configAttr in configAttributes) {
                    result.Start("entry")
                        .Elem("name", configAttr.Name)
                        .Elem("valuetype", configAttr.ValueType)
                        .Elem("description", configAttr.Description)
                    .End();
                }
                result.End();
            }

            // retrieve DreamFeature attributes on method definitions
            result.Start("features");
            MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            foreach(MethodInfo method in methods) {

                // retrieve feature description
                Attribute[] featureAttributes = Attribute.GetCustomAttributes(method, typeof(DreamFeatureAttribute), false);
                if(featureAttributes.Length == 0) {
                    continue;
                }
                if(method.IsGenericMethod || method.IsGenericMethodDefinition) {
                    throw new NotSupportedException(string.Format("generic methods are not supported ({0})", method.Name));
                }

                // determine access level
                string access;
                if(method.IsPublic) {
                    access = "public";
                } else if(method.IsAssembly) {
                    access = "internal";
                } else if(method.IsPrivate || method.IsFamily) {
                    access = "private";
                } else {
                    throw new NotSupportedException(string.Format("access level is not supported ({0})", method.Name));
                }

                // retrieve feature parameter descriptions, filters, prologues, and epilogues
                Attribute[] paramAttributes = Attribute.GetCustomAttributes(method, typeof(DreamFeatureParamAttribute), false);
                var pathAttributes = method.GetParameters().Select(p => {
                    var attr = (PathAttribute)p.GetCustomAttributes(typeof(PathAttribute), false).FirstOrDefault();
                    return ((attr != null) && (attr.Name == null)) ? new PathAttribute { Description = attr.Description, Name = p.Name } : attr;
                }).Where(p => p != null);
                var queryAttributes = method.GetParameters().Select(q => {
                    var attr = (QueryAttribute)q.GetCustomAttributes(typeof(QueryAttribute), false).FirstOrDefault();
                    return ((attr != null) && (attr.Name == null)) ? new QueryAttribute { Description = attr.Description, Name = q.Name } : attr;
                }).Where(q => q != null);
                Attribute[] statusAttributes = Attribute.GetCustomAttributes(method, typeof(DreamFeatureStatusAttribute), false);
                foreach(DreamFeatureAttribute featureAttrib in featureAttributes) {
                    result.Start("feature");
                    result.Elem("obsolete", featureAttrib.Obsolete);
                    result.Elem("pattern", featureAttrib.Pattern);
                    result.Elem("description", featureAttrib.Description);
                    string info = featureAttrib.Info ?? serviceAttrib.Info;
                    if(info != null) {
                        result.Elem("info", info);
                    }
                    result.Elem("method", method.Name);

                    // add parameter descriptions (as seen on the method definition)
                    foreach(DreamFeatureParamAttribute paramAttrib in paramAttributes) {
                        result.Start("param");
                        result.Elem("name", paramAttrib.Name);
                        if(!string.IsNullOrEmpty(paramAttrib.ValueType)) {
                            result.Elem("valuetype", paramAttrib.ValueType);
                        }
                        result.Elem("description", paramAttrib.Description);
                        result.End();
                    }

                    // add parameter descriptions (as seen on the method parameters)
                    foreach(PathAttribute pathAttrib in pathAttributes) {
                        result.Start("param")
                            .Elem("name", "{" + pathAttrib.Name + "}")
                            .Elem("description", pathAttrib.Description)
                        .End();
                    }

                    // add parameter descriptions (as seen on the method parameters)
                    foreach(QueryAttribute queryAttrib in queryAttributes) {
                        result.Start("param")
                            .Elem("name", queryAttrib.Name)
                            .Elem("description", queryAttrib.Description)
                        .End();
                    }

                    // add status codes
                    foreach(DreamFeatureStatusAttribute paramAttrib in statusAttributes) {
                        result.Start("status");
                        result.Attr("value", (int)paramAttrib.Status);
                        result.Value(paramAttrib.Description);
                        result.End();
                    }

                    // add access level
                    result.Elem("access", access);
                    result.End();
                }
            }
            result.End();
            return result.EndAll();
        }
        public virtual Yield GetServiceInfo(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            XDoc   blueprint = Blueprint;
            string title     = blueprint["name"].AsText ?? "Service Blueprint";
            XDoc   result    = new XDoc("html").Attr("xmlns", "http://www.w3.org/1999/xhtml")
                               .Start("head")
                               .Elem("title", title)
                               .Start("meta").Attr("http-equiv", "content-type").Attr("content", "text/html;charset=utf-8").End()
                               .Start("meta").Attr("http-equiv", "Content-Style-Type").Attr("content", "text/css").End()
                               .End();

            if (blueprint.IsEmpty)
            {
                result.Elem("body", "Missing service blueprint");
            }
            else
            {
                result.Start("body")
                .Elem("h1", title)
                .Start("p")
                .Value(blueprint["copyright"].Contents)
                .Value(" ")
                .Start("a").Attr("href", blueprint["info"].Contents).Value("(more)").End()
                .Value(" ")
                .Start("a").Attr("href", Self.Uri.At("@blueprint").Path).Value("(blueprint)").End()
                .End();

                // show configuration information
                XDoc config = blueprint["configuration"];
                if (!config.IsEmpty)
                {
                    result.Elem("h2", "Configuration");
                    result.Start("ul");
                    foreach (XDoc entry in config["entry"])
                    {
                        result.Start("li");
                        if (entry["valuetype"].Contents != string.Empty)
                        {
                            result.Value(string.Format("{0} = {1} : {2}", entry["name"].Contents, entry["valuetype"].Contents, entry["description"].Contents));
                        }
                        else
                        {
                            result.Value(string.Format("{0} : {1}", entry["name"].Contents, entry["description"].Contents));
                        }
                        result.End();
                    }
                    result.End();
                }

                // sort features by signature then verb
                blueprint["features"].Sort(delegate(XDoc first, XDoc second) {
                    string[] firstPattern  = first["pattern"].Contents.Split(new[] { ':' }, 2);
                    string[] secondPattern = second["pattern"].Contents.Split(new[] { ':' }, 2);
                    int cmp = firstPattern[1].CompareInvariantIgnoreCase(secondPattern[1]);
                    if (cmp != 0)
                    {
                        return(cmp);
                    }
                    return(firstPattern[0].CompareInvariant(secondPattern[0]));
                });

                // display features
                XDoc features = blueprint["features/feature"];
                if (!features.IsEmpty)
                {
                    result.Elem("h2", "Features");
                    List <string> modifiers = new List <string>();
                    foreach (XDoc feature in features)
                    {
                        modifiers.Clear();

                        // add modifiers
                        string modifier = feature["access"].AsText;
                        if (modifier != null)
                        {
                            modifiers.Add(modifier);
                        }
                        modifier = feature["obsolete"].AsText;
                        if (modifier != null)
                        {
                            modifiers.Add("OBSOLETE => " + modifier);
                        }
                        if (modifiers.Count > 0)
                        {
                            modifier = " (" + string.Join(", ", modifiers.ToArray()) + ")";
                        }
                        else
                        {
                            modifier = string.Empty;
                        }

                        // check if feature has GET verb and no path parameters
                        string pattern = feature["pattern"].Contents;
                        if (pattern.StartsWithInvariantIgnoreCase(Verb.GET + ":") && (pattern.IndexOfAny(new[] { '{', '*', '?' }) == -1))
                        {
                            string[] parts = pattern.Split(new[] { ':' }, 2);
                            result.Start("h3")
                            .Start("a").Attr("href", context.AsPublicUri(Self.Uri.AtPath(parts[1])))
                            .Value(feature["pattern"].Contents)
                            .End()
                            .Value(modifier)
                            .End();
                        }
                        else
                        {
                            result.Elem("h3", feature["pattern"].Contents + modifier);
                        }
                        result.Start("p")
                        .Value(feature["description"].Contents)
                        .Value(" ")
                        .Start("a").Attr("href", feature["info"].Contents).Value("(more)").End();
                        XDoc paramlist = feature["param"];
                        if (!paramlist.IsEmpty)
                        {
                            result.Start("ul");
                            foreach (XDoc param in paramlist)
                            {
                                result.Start("li");
                                if (param["valuetype"].Contents != string.Empty)
                                {
                                    result.Value(string.Format("{0} = {1} : {2}", param["name"].Contents, param["valuetype"].Contents, param["description"].Contents));
                                }
                                else
                                {
                                    result.Value(string.Format("{0} : {1}", param["name"].Contents, param["description"].Contents));
                                }
                                result.End();
                            }
                            result.End();
                        }
                        result.End();
                    }
                }
            }
            response.Return(DreamMessage.Ok(MimeType.HTML, result.ToString()));
            yield break;
        }
Esempio n. 22
0
        private void LoadGroups(string tMainWebWikiDataPath)
        {
            foreach (string groupFileName in Directory.GetFiles(tMainWebWikiDataPath, "*Group.txt"))
            {
                string groupName = Path.GetFileNameWithoutExtension(Path.GetFileName(groupFileName));
                
                string groupContent = File.ReadAllText(groupFileName);

                TWikiGroup group = null;
                _convertedGroups.TryGetValue(groupName, out group);
                if (group == null)
                {
                    group = new TWikiGroup(true, groupName);
                }

                string[] members = ExtractNamesList(groupContent, "GROUP");

                foreach (string member in members)
                {
                    group.AddMemeber(member);
                }

                _convertedGroups[groupName] = group;
            }

            DreamMessage msg = _dekiPlug.At("groups").With("limit", int.MaxValue).GetAsync().Wait();
            if (msg.Status != DreamStatus.Ok)
            {
                WriteErrorResponse(msg, "Error while reciving groups from Deki. Groups not converted.");
                return;
            }
            Dictionary<string, string> dekiGroups = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);

            XDoc groupsDoc = msg.AsDocument();
            foreach (XDoc groupDoc in groupsDoc["//group"])
            {
                string dekiGroupName = groupDoc["groupname"].AsText;
                dekiGroups[dekiGroupName.ToLower()] = null;
            }

            foreach (string groupName in _convertedGroups.Keys)
            {
                TWikiGroup group = _convertedGroups[groupName];
                if (group.IsNewGroup)
                {
                    int groupNum = 0;
                    string dekiGroupName = groupName;
                    while (dekiGroups.ContainsKey(dekiGroupName))
                    {
                        groupNum++;
                        dekiGroupName = groupName + groupNum.ToString();
                    }
                    if (dekiGroupName != groupName)
                    {
                        WriteLineToConsole("TWiki group \"" + groupName + "\" converted as \"" + dekiGroupName + "\" becouse of existing same group in Deki");
                    }
                    group.DekiName = dekiGroupName;

                    XDoc newGroupDoc = new XDoc("group");
                    newGroupDoc.Elem("name", group.DekiName);

                    TWikiUser[] members = GetAllGroupMembers(groupName);
                    if (members.Length > 0)
                    {
                        newGroupDoc.Start("users");
                        foreach (TWikiUser member in members)
                        {
                            newGroupDoc.Start("user").Attr("id", member.DekiId).End();
                        }
                        newGroupDoc.End();
                    }

                    DreamMessage res = _dekiPlug.At("groups").PostAsync(newGroupDoc).Wait();
                    WriteErrorResponse(res, "Error converting group\"" + groupName + "\"");
                }
                else
                {
                    XDoc updateGroupDoc = new XDoc("users");
                    TWikiUser[] members = GetAllGroupMembers(groupName);
                    if (members.Length > 0)
                    {
                        foreach (TWikiUser member in members)
                        {
                            updateGroupDoc.Start("user").Attr("id", member.DekiId).End();
                        }
                    }
                    DreamMessage res = _dekiPlug.At("groups", "=" + group.DekiName, "users").PutAsync(updateGroupDoc).Wait();
                    WriteErrorResponse(res, "Error updating group \"" + groupName + "\" users.");
                }
            }
        }
        public XDoc Table(
            [DekiExtParam("path", true)] string path,
            [DekiExtParam("revision range", true)] string range,
            [DekiExtParam("limit to maximum entries", true)] int? limit,
            [DekiExtParam("show full log message (default: false)", true)] bool? verbose,
            [DekiExtParam("stop on copy (default: true)", true)] bool? stoponcopy

        ) {
            XDoc svnRet = SvnLog(limit, false, path, range, stoponcopy);
            XDoc ret = new XDoc("html");
            ret.Start("body")
               .Start("div").Attr("class", "DW-table SVN-table table")
               .Start("table").Attr("border", 0).Attr("cellspacing", 0).Attr("cellpadding", 0).Attr("class", "table");

            // header
            ret.Start("tr")
                .Elem("th", "Revision")
                .Elem("th", "Date")
                .Elem("th", "Author")
                .Elem("th", "Message")
            .End();
            int count = 0;
            foreach (XDoc revision in svnRet["logentry"]) {
                string msg = revision["msg"].AsText ?? string.Empty;
                msg = msg.Trim();
                string tdClass = count % 2 == 0 ? "bg1" : "bg2";
                if (!(verbose ?? false)) {

                    //Trim the msg at a work boundary
                    int linebreak = StringUtil.IndexOfInvariantIgnoreCase(msg, "\n");
                    int cutoff;
                    if (linebreak > 0)
                        cutoff = Math.Min(linebreak, DEFAULT_LIMIT);
                    else
                        cutoff = DEFAULT_LIMIT;
                    while (msg.Length > cutoff && cutoff - DEFAULT_MSG_LENGTH <= 10) {
                        if (char.IsWhiteSpace(msg[cutoff]))
                            break;
                        cutoff++;
                    }

                    if (msg.Length > cutoff) {
                        msg = string.Format("{0} …", msg.Substring(0, Math.Min(msg.Length - 1, cutoff)));
                    }
                }

                DateTime d = revision["date"].AsDate ?? DateTime.MinValue;
                string date = d.ToString(DreamContext.Current.Culture);
                ret.Start("tr");
                ret.Start("td").Attr("class", tdClass);
                OutputRevLink(ret, revision["@revision"].AsText).End();
                ret.Start("td").Attr("class", tdClass).Value(date).End();
                ret.Start("td").Attr("class", tdClass).Value(revision["author"].AsText).End();
                ret.Start("td").Attr("class", tdClass);
                ParseRevMessage(ret, msg).End();
                ret.End();//tr

                count++;
            }

            ret.End();//body
            ret.End();//table
            ret.End();//div

            return ret;
        }
Esempio n. 24
0
        public Yield GetNavigationChildren(DreamContext context, DreamMessage request, Result<DreamMessage> response) {
            CheckResponseCache(context, false);

            PageBE page = PageBL_GetPageFromUrl(context, false);
            if (page.Title.IsTalk) {
                page = PageBL.GetPageByTitle(page.Title.AsFront());
            }

            // build response
            uint exclude = context.GetParam<uint>("exclude", 0);
            IList<NavBE> list = NavBL.QueryNavChildrenData(page, context.Culture);
            if(ShowDebug(context)) {
                response.Return(DreamMessage.Ok(NavBL.ConvertNavPageListToDoc(list)));
            } else {
                bool expandableNav = context.GetParam("type", "compact").EqualsInvariantIgnoreCase("expandable");
                XDoc doc = expandableNav ? NavBL.ComputeExpandableNavigationDocument(list, page, 0, exclude, true) : NavBL.ComputeNavigationDocument(list, page, 0, exclude, true, context.GetParam("width", int.MaxValue));
                if(ShowXml(context)) {
                    response.Return(DreamMessage.Ok(doc));
                } else {
                    XDoc result = new XDoc("tree");
                    result.Start("children");

                    // add name of children nodes
                    System.Text.StringBuilder nodes = new System.Text.StringBuilder();
                    ulong homepageId = DekiContext.Current.Instance.HomePageId;
                    ulong parentId = (page.ID == homepageId) ? 0 : page.ID;
                    foreach(NavBE child in list) {
                        if((child.ParentId == parentId) && (child.Id != homepageId)) {
                            if(nodes.Length != 0) {
                                nodes.Append(",");
                            }
                            nodes.AppendFormat("n{0}", child.Id);
                        }
                    }
                    result.Elem("nodes", nodes.ToString());

                    // add <div> list
                    result.Start("html");
                    if(exclude != 0) {
                        result.Start("pre").Value(doc["children-pre"].Contents).End();
                        result.Start("post").Value(doc["children-post"].Contents).End();
                    } else {
                        result.Value(doc.Contents);
                    }
                    result.End();
                    result.End();
                    response.Return(DreamMessage.Ok(result));
                }
            }
            yield break;
        }
Esempio n. 25
0
        public XDoc Table(
            [DekiExtParam("SELECT query")] string query
        ) {
            XDoc result = new XDoc("html")
                .Start("head")
                    .Start("script").Attr("type", "text/javascript").Attr("src", Files.At("sorttable.js")).End()
                    .Start("style").Attr("type", "text/css").Value(@".feedtable {
    border:1px solid #999;
    line-height:1.5em;
    overflow:hidden;
    width:100%;
}
.feedtable th {
    background-color:#ddd;
    border-bottom:1px solid #999;
    font-size:14px;
}
.feedtable tr {
    background-color:#FFFFFF;
}
.feedtable tr.feedroweven td {
    background-color:#ededed;
}").End()
                .End()
                .Start("body");
            result.Start("table").Attr("border", 0).Attr("cellpadding", 0).Attr("cellspacing", 0).Attr("class", "feedtable sortable");
            _catalog.NewQuery(query).Execute(delegate(IDataReader reader) {

                // capture row columns
                result.Start("thead").Start("tr");
                int count = reader.FieldCount;
                for(int i = 0; i < count; ++i) {
                    result.Start("th").Elem("strong", reader.GetName(i)).End();
                }
                result.End().End();

                // read records
                int rowcount = 0;
                result.Start("tbody");
                while(reader.Read()) {
                    result.Start("tr");
                    result.Attr("class", ((rowcount++ & 1) == 0) ? "feedroweven" : "feedrowodd");
                    for (int i = 0; i < count; ++i) {
                        string val = string.Empty;

                        try {
                            if (!reader.IsDBNull(i)) {
                                val = reader.GetValue(i).ToString();
                            }
                        } catch { }
                     
                        result.Elem("td", val);
                    }
                    result.End();
                }
                result.End();
            });
            result.End().End();
            return result;
        }
Esempio n. 26
0
        /// <summary>
        /// Read a Versit string from a text reader and parse it into an Xml document.
        /// </summary>
        /// <param name="reader">Source reader.</param>
        /// <param name="root">Name to use as thexml document root node.</param>
        /// <returns>Xml document instance.</returns>
        public static XDoc FromVersit(TextReader reader, string root)
        {
            string value = reader.ReadToEnd().Trim();
            XDoc result = new XDoc(string.IsNullOrEmpty(root) ? "root" : root);

            // NOTE (steveb): the versit format is "KEY;ATTR_KEY=ATTR_VALUE;ATTR_KEY=ATTR_VALUE:VALUE\r\n"

            // join line continuations
            value = value.Replace("\r\n ", "");

            // split lines
            string[] lines = value.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

            // process each line
            foreach(string line in lines) {
                if(line.StartsWithInvariant("BEGIN:")) {
                    result.Start(line.Substring(6).ToLowerInvariant());
                } else if(line.StartsWithInvariant("END:")) {
                    result.End();
                } else {
                    string[] pair = line.Split(new[] { ':' }, 2);
                    string[] attrs = pair[0].Split(';');
                    result.Start(attrs[0].ToLowerInvariant());
                    for(int i = 1; i < attrs.Length; ++i) {
                        string[] attr = attrs[i].Split(new[] { '=' }, 2);
                        result.Attr(attr[0].ToLowerInvariant(), (attr.Length > 1) ? DecodeVersitString(attr[1]) : string.Empty);
                    }
                    if(pair.Length > 1) {
                        result.Value(DecodeVersitString(pair[1]));
                    }
                    result.End();
                }
            }
            return result;
        }
Esempio n. 27
0
        //--- Methods ---
        private void AddFunction(XDoc result, string ns, XDoc function) {
            result.Start("blockquote");
            List<Tuplet<string, bool, string, string>> args = new List<Tuplet<string, bool, string, string>>();
            StringBuilder signature = new StringBuilder();
            signature.Append(((ns != null) ? ns + "." : string.Empty) + function["name"].AsText);
            if(string.IsNullOrEmpty(function["@usage"].AsText)) {
                signature.Append("(");

                // enumerate arguments
                int count = 1;
                foreach(XDoc arg in function["param"]) {

                    // add argument to signature
                    if(count > 1) {
                        signature.Append(", ");
                    }
                    string name = arg["@name"].AsText ?? arg["name"].AsText ?? ("arg" + count.ToString());
                    signature.Append(name);
                    string type = arg["@type"].AsText ?? arg["type"].AsText;
                    if(type != null) {
                        signature.Append(" : ");
                        signature.Append(type);
                    }
                    ++count;

                    // add argument to explanation
                    if(!arg["hint"].IsEmpty || !string.IsNullOrEmpty(arg.AsText)) {
                        args.Add(new Tuplet<string, bool, string, string>(name, StringUtil.EqualsInvariant(arg["@optional"].AsText, "true") || !arg["@default"].IsEmpty || !arg["hint[@optional='true']"].IsEmpty, arg["hint"].AsText ?? arg.AsText, arg["@default"].AsText));
                    }
                }
                signature.Append(")");
            }
            signature.Append(" : ").Append(function["return/@type"].AsText ?? "any");
            result.Elem("h3", signature.ToString());
            if(function["description"].AsText != null) {
                result.Elem("p", function["description"].AsText);
            }

            // add argument explanation
            if(args.Count > 0) {
                result.Start("ul");
                foreach(Tuplet<string, bool, string, string> arg in args) {
                    result.Start("li");
                    result.Elem("strong", arg.Item1);
                    if(arg.Item2) {
                        result.Value(" (optional)");
                    }
                    result.Value(": " + arg.Item3);
                    if(arg.Item4 != null) {
                        result.Value(" (default: " + arg.Item4 + ")");
                    }
                    result.End();
                }
                result.End();
            }
            result.Elem("br");
            result.End();
        }
Esempio n. 28
0
 private static void FixupManifest(XDoc manifest, Opts opts) {
     if(opts.ImportOnce) {
         manifest.Attr("import-once", true);
     }
     if(opts.InitOnly) {
         manifest.Attr("init-only", true);
     }
     if(manifest["@preserve-local"].IsEmpty) {
         manifest.Attr("preserve-local", opts.PreserveLocalChanges ?? false);
     } else {
         manifest["@preserve-local"].ReplaceValue(opts.PreserveLocalChanges ?? false);
     }
     if(opts.Restriction != Restriction.Default) {
         manifest.Start("security")
             .Start("permissions.page")
                 .Elem("restriction", GetRestrictionString(opts.Restriction))
             .End()
         .End();
     }
     foreach(var capability in opts.Capabilities) {
         manifest.Start("capability").Attr("name", capability.Key);
         if(!string.IsNullOrEmpty(capability.Value)) {
             manifest.Attr("value", capability.Value);
         }
         manifest.End();
     }
 }
Esempio n. 29
0
        public Yield GetSiteFunctions(DreamContext context, DreamMessage request, Result<DreamMessage> response) {
            PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.UPDATE);

            // build set of libraries
            List<XDoc> libraries = DekiContext.Current.Instance.RunningServices.ExtensionServices
                .Select(x => x.Extension.Manifest).ToList();

            // add registered libraries
            libraries.Sort((left, right) => left["title"].Contents.CompareInvariantIgnoreCase(right["title"].Contents));

            // add built-in functions
            XDoc builtinlib = new XDoc("extension");
            builtinlib.Elem("title", "Built-in Functions");
            builtinlib.Elem("label", "Built-in");
            builtinlib.Elem("uri.help", "http://wiki.developer.mindtouch.com/MindTouch_Deki/DekiScript/Reference");
            builtinlib.Elem("description", "The following functions and variables are part the DekiScript and MindTouch runtime environment.");
            foreach(var function in ScriptRuntime.Functions.Values) {
                if(function.Access == DreamAccess.Public) {
                    builtinlib.Add(function.ToXml(null));
                }
            }
            libraries.Insert(0, builtinlib);

            // create composite document
            bool hasUnsafeContentPermission = PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.UNSAFECONTENT);
            XDoc extensions = new XDoc("extensions").AddAll(libraries);
            foreach(XDoc extension in extensions["extension"]) {
                XUri serviceUri = extension["@uri"].AsUri;

                // check if extension is protected
                bool @protected;
                bool.TryParse(ExtensionBL.GetExtensionPreference(serviceUri, "protected"), out @protected);
                if(@protected) {
                    if(!hasUnsafeContentPermission) {
                        extension.Remove();
                        continue;
                    }
                    extension.Attr("protected", @protected);
                }

                // read overwriteable settings
                AddOrReplace(extension, "title", ExtensionBL.GetExtensionPreference(serviceUri, "title.custom"));
                AddOrReplace(extension, "uri.logo", ExtensionBL.GetExtensionPreference(serviceUri, "uri.logo.custom"));
                AddOrReplace(extension, "namespace", ExtensionBL.GetExtensionPreference(serviceUri, "namespace.custom"));
                extension.Elem("description.custom", ExtensionBL.GetExtensionPreference(serviceUri, "description.custom"));

                // check which functions to keep
                string[] allowedFunctions = (ExtensionBL.GetExtensionPreference(serviceUri, "functions") ?? string.Empty).Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
                if(allowedFunctions.Length > 0) {
                    foreach(XDoc function in extension["function"]) {

                        // check if user specified a list of functions to show
                        string name = function["name"].Contents;
                        if(Array.FindIndex(allowedFunctions, current => current.EqualsInvariantIgnoreCase(name)) < 0) {
                            function.Remove();
                        }
                    }
                }

                // check if extension has any functions
                if(extension["function"].ListLength == 0) {
                    extension.Remove();
                }
            }

            // build response document
            string format = context.GetParam("format", "html");
            if(StringUtil.EqualsInvariant(format, "xml")) {
                response.Return(DreamMessage.Ok(extensions));
            } else {

                // prepare document
                string header = string.Format("{0} - Registered Extensions", DekiContext.Current.Instance.SiteName);
                XDoc result = new XDoc("html").Attr("xmlns", "http://www.w3.org/1999/xhtml")
                    .Start("head")
                        .Elem("title", header)
                        .Start("meta").Attr("http-equiv", "content-type").Attr("content", "text/html;charset=utf-8").End()
                    .End();
                result.Start("body");
                result.Elem("h1", header);

                // build table of contents
                result.Elem("strong", "Table of Contents");
                result.Start("ol");
                int count = 0;
                foreach(XDoc library in extensions["extension"]) {
                    ++count;
                    XUri serviceUri = library["@uri"].AsUri;
                    result.Start("li").Start("a").Attr("href", "#section" + count).Value(ExtensionBL.GetExtensionPreference(serviceUri, "title.custom") ?? library["title"].AsText).End().End();
                }
                result.End();

                // enumerate libraries
                count = 0;
                foreach(XDoc library in extensions["extension"]) {
                    ++count;

                    // read overwriteable settings
                    string title = library["title"].AsText;
                    string logo = library["uri.logo"].AsText;
                    string ns = library["namespace"].AsText;
                    bool @protected = library["@protected"].AsBool ?? false;

                    // show & link library name
                    result.Start("h2").Attr("id", "section" + count);
                    if(!string.IsNullOrEmpty(library["uri.help"].AsText)) {
                        result.Start("a").Attr("href", library["uri.help"].AsText).Attr("target", "_blank").Attr("title", library["title"].AsText + " Documentation").Value(title).End();
                    } else {
                        result.Value(title);
                    }
                    if(@protected) {
                        result.Value(string.Format(" ({0})", DekiResources.PROTECTED));
                    }
                    result.End();

                    // show optional logo
                    if(!string.IsNullOrEmpty(logo)) {
                        result.Start("img").Attr("src", logo).Attr("alt", title).End();
                    }

                    // show descriptions
                    if(library["uri.license"].AsText != null) {
                        result.Start("a").Attr("href", library["uri.license"].AsText).Attr("target", "_blank").Value("Read Library License").End();
                    }
                    if(!string.IsNullOrEmpty(library["description"].AsText)) {
                        result.Elem("p", library["description"].AsText);
                    }
                    if(!string.IsNullOrEmpty(library["description.custom"].AsText)) {
                        result.Elem("p", library["description.custom"].AsText);
                    }

                    // enumerate library functions
                    XDoc functions = new XDoc("functions").AddAll(library["function"]);
                    functions.Sort(delegate(XDoc left, XDoc right) {
                        return StringUtil.CompareInvariantIgnoreCase(left["name"].Contents, right["name"].Contents);
                    });
                    foreach(XDoc function in functions["function"]) {
                        AddFunction(result, ns, function);
                    }
                }
                result.End();
                switch(format) {
                default:
                case "html":
                    response.Return(DreamMessage.Ok(MimeType.HTML, result.ToString()));
                    break;
                case "body":
                    response.Return(DreamMessage.Ok(MimeType.TEXT_UTF8, result["body"].Contents));
                    break;
                }
            }
            yield break;
        }
Esempio n. 30
0
        private XDoc BuildBugListHTMLTable(XmlRpcStruct[] bugs, int[] ticketIds) {
            XDoc ret = new XDoc("div").Attr("class", "DW-table Trac-table table");
            ret.Start("table").Attr("border", 0).Attr("cellspacing", 0).Attr("cellpadding", 0).Attr("class", "table feedtable sortable");

            // header
            ret.Start("tr")
                .Elem("th", "Bug#")
                .Elem("th", "Summary")
                .Elem("th", "Status")
                .Elem("th", "Severity")
                .Elem("th", "Opened By")
                .Elem("th", "Assigned To")

            .End();

            for(int i=0; i < bugs.Length; i++){
                XmlRpcStruct bug = bugs[i];
                string status = bug["status"].ToString();
                string reporter = bug["reporter"].ToString();

                // The severity-param is not submitted by trac if no severity-entry is defined
                string severity = string.Empty;
                if(bug["severity"] != null) {
                    severity = bug["severity"].ToString();
                }
                string owner = bug["owner"].ToString();
                string summary = bug["summary"].ToString();

                string trClass = string.Format("{0} {1}", (i % 2 == 0) ? "even" : "odd", status);
                ret.Start("tr").Attr("class", trClass);
                ret.Start("td");
                ret = BuildBugLink(bug, ret, ticketIds[i]);
                ret.End(); //td;
                ret.Elem("td", summary);
                ret.Start("td").Value(status).End();
                ret.Start("td").Value(severity).End();
                ret.Elem("td", reporter);
                ret.Elem("td", owner);

                ret.End();//tr
            }
            ret.End(); // table
            return ret;
        }
Esempio n. 31
0
        public static DreamMessage CreateGroup(Plug p, string role, string[] memberUserIds, out string id, string name)
        {
            XDoc groupDoc = new XDoc("group")
                .Elem("groupname", name)
                .Start("permissions.group")
                    .Elem("role", role)
                .End();

            if (memberUserIds != null && memberUserIds.Length > 0)
            {
                groupDoc.Start("users");
                foreach (string userid in memberUserIds)
                    groupDoc.Start("user").Attr("id", userid).End();
                groupDoc.End();
            }

            DreamMessage msg = p.At("groups").Post(groupDoc);
            id = msg.ToDocument()["@id"].AsText;
            return msg;
        }
Esempio n. 32
0
        public XDoc FeedEntries(
            [DekiExtParam("feed uri (Atom or RSS) (default: nil)", true)] XUri feed,
            [DekiExtParam("max number of entries to read (default: 20)", true)] int? max,
            [DekiExtParam("publish on channel (default: \"default\")", true)] string publish,
            [DekiExtParam("subscribe to channel (default: nil)", true)] string subscribe
        ) {

            // check key
            string key = GoogleApiKey;
            if(string.IsNullOrEmpty(key)) {
                return new XDoc("html").Start("body").Start("span").Attr("style", "color:red;font-weight:bold;").Value("The Google API key is missing").End().End();
            }

            // initialize feed loader
            string id = StringUtil.CreateAlphaNumericKey(8);
            XDoc result = new XDoc("html");
            result.Start("head");
            result.Start("script").Attr("type", "text/javascript").Attr("src", new XUri("http://www.google.com/jsapi").With("key", key)).End();
            result.Start("script").Attr("type", "text/javascript").Value("google.load('feeds', '1');").End();
            result.Start("script").Attr("type", "text/javascript").Value(
@"function google_feed_data(c, m, d) {
    if((typeof(m.uri) != 'undefined') && (m.uri != null) && (m.uri != '')) {
        var feed = new google.feeds.Feed(m.uri);
        feed.setNumEntries(d.max);
        feed.load(function(r) {
            if(!r.error) {
                for(var i = 0; i < r.feed.entries.length; ++i) {
                    var entry = r.feed.entries[i];
                    Deki.publish(d.channel, { label: entry.title, uri: entry.link, html: entry.content, text: entry.contentSnippet, date: entry.publishedDate, name: r.feed.author });
                }
            } else {
                Deki.publish('debug', { text: 'An error occurred while retrieving the feed for uri = ' + uri + '; code = ' + r.error.code + '; message = ' + r.error.message });
            }
        });
    }
}"
            ).End();
            if(subscribe != null) {
                result.Start("script").Attr("type", "text/javascript").Value("Deki.subscribe('{subscribe}', null, google_feed_data, { max: {max}, channel: '{channel}' });".Replace("{subscribe}", StringUtil.EscapeString(subscribe)).Replace("{max}", (max ?? 20).ToString()).Replace("{channel}", StringUtil.EscapeString(publish ?? "default"))).End();
            }
            result.Start("script").Attr("type", "text/javascript").Value("Deki.subscribe('{id}', null, google_feed_data, { max: {max}, channel: '{channel}' });".Replace("{id}", id).Replace("{max}", (max ?? 20).ToString()).Replace("{channel}", StringUtil.EscapeString(publish ?? "default"))).End();
            result.End();
            if(feed != null) {
                result.Start("tail")
                    .Start("script").Attr("type", "text/javascript").Value("Deki.publish('{id}', { uri: '{feed}' });".Replace("{id}", id).Replace("{feed}", feed.ToString())).End()
                .End();
            }
            return result;
        }
        //--- Methods ---
        public Yield GetPageData(uint pageId, string wikiId, DateTime time, CultureInfo culture, string timezone, Result<PageChangeData> result) {

            // Note (arnec): going back 10 seconds before event, because timestamps in a request are not currently synced
            Result<PageChangeCacheData> cacheResult;
            yield return cacheResult = Coroutine.Invoke(GetCache, pageId, wikiId, time, culture, new Result<PageChangeCacheData>());
            PageChangeCacheData cacheData = cacheResult.Value;
            if(cacheData == null) {
                result.Return((PageChangeData)null);
                yield break;
            }
            StringBuilder plainBody = new StringBuilder();
            plainBody.AppendFormat("{0}\r\n[ {1} ]\r\n\r\n", cacheData.Title, cacheData.PageUri);
            XDoc htmlBody = new XDoc("html")
                .Start("p")
                    .Start("b")
                        .Start("a").Attr("href", cacheData.PageUri).Value(cacheData.Title).End()
                    .End()
                    .Value(" ( Last edited by ")
                    .Start("a").Attr("href", cacheData.WhoUri).Value(cacheData.Who).End()
                    .Value(" )")
                    .Elem("br")
                    .Start("small")
                        .Start("a").Attr("href", cacheData.PageUri).Value(cacheData.PageUri).End()
                    .End()
                    .Elem("br")
                    .Start("small")
                        .Start("a").Attr("href", cacheData.UnsubUri).Value("Unsubscribe").End()
                    .End()
                .End()
                .Start("p")
                    .Start("ol");
            string tz = "GMT";
            TimeSpan tzOffset = TimeSpan.Zero;
            if(!string.IsNullOrEmpty(timezone)) {
                tz = timezone;
                string[] parts = timezone.Split(':');
                int hours;
                int minutes;
                int.TryParse(parts[0], out hours);
                int.TryParse(parts[1], out minutes);
                tzOffset = new TimeSpan(hours, minutes, 0);
            }
            foreach(PageChangeCacheData.Item item in cacheData.Items) {
                string t = item.Time.Add(tzOffset).ToString(string.Format("ddd, dd MMM yyyy HH':'mm':'ss '{0}'", tz), culture);
                plainBody.AppendFormat(" - {0} by {1} ({2})\r\n", item.ChangeDetail, item.Who, t);
                plainBody.AppendFormat("   [ {0} ]\r\n", item.RevisionUri);

                htmlBody.Start("li")
                            .Value(item.ChangeDetail)
                            .Value(" ( ")
                            .Start("a").Attr("href", item.RevisionUri).Value(t).End()
                            .Value(" by ")
                            .Start("a").Attr("href", item.WhoUri).Value(item.Who).End()
                            .Value(" )")
                        .End();
                plainBody.Append("\r\n");
            }
            htmlBody
                    .End()
                .End()
                .Elem("br");
            result.Return(new PageChangeData(plainBody.ToString(), htmlBody));
            yield break;
        }
Esempio n. 34
0
        private void AppendDiff(bool diffCacheEnabled, XDoc body, RecentChangeEntry change, RC type, Title title, IDictionary<string, XDoc> cache) {
            var resources = DekiContext.Current.Resources;
            ulong pageid = change.CurId;
            int? after = (change.Revision > 0) ? (int?)change.Revision : null;
            int? before = change.PreviousRevision;

            // append edit summary, if any
            body.Elem("p", change.Summary);

            // append comment(s)
            int count = (change.ExtraComments == null) ? (string.IsNullOrEmpty(change.Comment) ? 0 : 1) : change.ExtraComments.Count;
            switch(count) {
            case 0:

                // nothing to do
                break;
            case 1:
                body.Elem("p", (change.ExtraComments != null) ? change.ExtraComments[0].Item3 : change.Comment);
                break;
            default:
                body.Start("ol");
                foreach(var comment in ((IEnumerable<Tuplet<string, string, string>>)change.ExtraComments).Reverse()) {
                    string author = string.IsNullOrEmpty(comment.Item2) ? comment.Item1 : comment.Item2;
                    body.Elem("li", string.IsNullOrEmpty(author) ? comment.Item3 : string.Format("{0} ({1})", comment.Item3, author));
                }
                body.End();
                break;
            }

            // check if page was modified
            if(after.HasValue && before.HasValue && (after != before)) {

                // check if we have a cached version of this page diff
                XDoc diffXml = null;
                Plug store = Storage.At("site_" + XUri.EncodeSegment(DekiContext.Current.Instance.Id), DreamContext.Current.Culture.Name, "feeds", string.Format("page_{0}", pageid), string.Format("diff_{0}-{1}.xml", before, after));
                if(diffCacheEnabled) {
                    var v = store.Get(new Result<DreamMessage>(TimeSpan.MaxValue)).Wait();
                    diffXml = (v.IsSuccessful && v.HasDocument) ? v.ToDocument() : null;

                    if(diffXml != null) {

                        // TODO (steveb): this problem only exists b/c we can't determine the actual revision number that we should use for diffing (see bug 7824)

                        // check if either revision has been hidden since we computed the diff
                        var session = DbUtils.CurrentSession;
                        if(after.Value != change.CurrentRevision) {
                            OldBE afterRevision = session.Old_GetOldByRevision(pageid, (ulong)after.Value);
                            if((afterRevision == null) || afterRevision.IsHidden) {
                                diffXml = null;
                            }
                        }
                        if((diffXml != null) && (before.Value != change.CurrentRevision) && (before.Value > 0)) {
                            OldBE beforeRevision = session.Old_GetOldByRevision(pageid, (ulong)before.Value);
                            if((beforeRevision == null) || beforeRevision.IsHidden) {
                                diffXml = null;
                            }
                        }
                    }
                }
                if(diffXml == null) {
                    diffXml = new XDoc("diff");

                    // retrieve page versions
                    XDoc res = QueryPageVersions(pageid, after, before, cache);
                    XDoc beforeDoc = res["before/body"];
                    XDoc afterDoc = res["after/body"];

                    // check if either both versions or only one version were retrieved
                    XDoc diff = XDoc.Empty;
                    XDoc invisibleDiff = XDoc.Empty;
                    string summary = null;
                    if(!beforeDoc.IsEmpty && !afterDoc.IsEmpty) {
                        XDoc beforeChanges;
                        XDoc afterChanges;
                        DekiResource summaryResource = null;

                        // compute differences between 'before' and 'after' versions
                        diff = Utils.GetPageDiff(beforeDoc, afterDoc, true, DekiContext.Current.Instance.MaxDiffSize, out invisibleDiff, out summaryResource, out beforeChanges, out afterChanges);

                        // TODO (arnec): why are we using ToLower here at all and without a culture?
                        summary = resources.Localize(summaryResource).ToLower();
                    } else if(!afterDoc.IsEmpty) {

                        // since we don't have a 'before' version, just show the entire 'after' version (can happen for new pages or hidden revisions)
                        diff = afterDoc;
                    } else if(!beforeDoc.IsEmpty) {

                        // since we don't have a 'after' version, just show the entire 'before' version (can happen for hidden revisions)
                        diff = beforeDoc;
                    }

                    // add change summary
                    diffXml.Start("blockquote");
                    diffXml.Start("p").Elem("strong", summary).End();

                    // check if a diff was computed
                    if(!diff.IsEmpty) {
                        diffXml.Start("hr").Attr("width", "100%").Attr("size", "2").End();
                        diffXml.AddNodes(diff);
                        diffXml.Start("hr").Attr("width", "100%").Attr("size", "2").End();

                        // check if there are invisible changes as well to show
                        if(!invisibleDiff.IsEmpty) {
                            diffXml.Start("p").Elem("strong", resources.Localize(DekiResources.PAGE_DIFF_OTHER_CHANGES())).End();
                            diffXml.Add(invisibleDiff);
                        }
                    } else if(!invisibleDiff.IsEmpty) {

                        // only show invisible changes
                        diffXml.Start("hr").Attr("width", "100%").Attr("size", "2").End();
                        diffXml.Start("p").Elem("strong", resources.Localize(DekiResources.PAGE_DIFF_OTHER_CHANGES())).End();
                        diffXml.Add(invisibleDiff);
                    } else if(beforeDoc.IsEmpty && afterDoc.IsEmpty) {

                        // show message that page contents were not available anymore
                        diffXml.Elem("p", resources.Localize(DekiResources.PAGE_NOT_AVAILABLE()));
                    }
                    diffXml.End();

                    // store diff in cache
                    if(diffCacheEnabled && !afterDoc.IsEmpty) {
                        store.With("ttl", TimeSpan.FromDays(30).TotalSeconds).Put(diffXml, new Result<DreamMessage>(TimeSpan.MaxValue)).Block();
                    }
                }
                body.AddNodes(diffXml);
            }

            // check if we have a comment text
            if(Utils.IsPageComment(type)) {
                string text = change.CmntContent;
                if(!string.IsNullOrEmpty(text) && !change.CmntDeleted) {
                    MimeType mime = new MimeType(change.CmntMimetype ?? MimeType.TEXT_UTF8.ToString());
                    if(mime.Match(MimeType.HTML)) {
                        XDoc html = XDocFactory.From(string.Format("<html><body>{0}</body></html>", text), MimeType.HTML);
                        body.Start("blockquote").AddNodes(html["body"]).End();
                    } else {

                        // anything else should be consider to be text
                        body.Start("blockquote").Elem("p", text).End();
                    }
                } else {

                    // anything else should be consider to be text
                    body.Start("blockquote").Elem("p", resources.Localize(DekiResources.COMMENT_NOT_AVAILABLE())).End();
                }
            }

            // adds links
            body.Start("table").Attr("border", 0).Attr("padding", "5").Attr("width", "80%").Start("tr");

            // add link for viewing the page
            if(change.PageExists) {
                Title view = new Title(title);
                body.Start("td").Start("a").Attr("href", Utils.AsPublicUiUri(view, true)).Value(resources.Localize(DekiResources.VIEW_PAGE())).End().End();
            }

            // check if we need to add link for editing the page
            if(after.HasValue && before.HasValue && (after != before)) {
                Title edit = new Title(title) { Query = "action=edit" };
                body.Start("td").Start("a").Attr("href", Utils.AsPublicUiUri(edit)).Value(resources.Localize(DekiResources.EDIT_PAGE())).End().End();
            }

            // check if we need to add link for viewing the complete diff
            if(after.HasValue && before.HasValue && (after != before)) {
                Title show = new Title(title) { Query = string.Format("diff={0}&revision={1}", after.Value, before.Value) };
                body.Start("td").Start("a").Attr("href", Utils.AsPublicUiUri(show, true)).Value(resources.Localize(DekiResources.VIEW_PAGE_DIFF())).End().End();
            }

            // check if we need to add link for seeing full page history
            if(after.HasValue && before.HasValue && (after != before)) {
                Title history = new Title(title) { Query = "action=history" };
                body.Start("td").Start("a").Attr("href", Utils.AsPublicUiUri(history)).Value(resources.Localize(DekiResources.VIEW_PAGE_HISTORY())).End().End();
            }

            // check if we need to add link for banning the user
            List<KeyValuePair<string, string>> authors = change.SortedAuthors;
            if((authors == null) || (authors.Count == 0)) {
                authors = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>(change.Username, change.Fullname) };
            }
            for(int i = 0; i < authors.Count; ++i) {
                string username = authors[i].Key;
                string fullname = authors[i].Value;
                if(!string.IsNullOrEmpty(username)) {

                    // don't put up ban link for admins.
                    UserBE user = DbUtils.CurrentSession.Users_GetByName(username);
                    if(!UserBL.IsAnonymous(user) && !PermissionsBL.IsUserAllowed(user, Permissions.ADMIN)) {
                        Title ban = Title.FromUIUri(null, "Special:Userban");
                        ban.Query += string.Format("username={0}", username);
                        body.Start("td").Start("a").Attr("href", Utils.AsPublicUiUri(ban)).Value(resources.Localize(DekiResources.BAN_USER(string.IsNullOrEmpty(fullname) ? username : fullname))).End().End();
                    }
                }
            }

            // close HTML
            body.End().End();
        }
Esempio n. 35
0
        public XDoc Table(
            [DekiExtParam("path", true)] string path,
            [DekiExtParam("revision range", true)] string range,
            [DekiExtParam("limit to maximum entries", true)] int?limit,
            [DekiExtParam("show full log message (default: false)", true)] bool?verbose,
            [DekiExtParam("stop on copy (default: true)", true)] bool?stoponcopy

            )
        {
            XDoc svnRet = SvnLog(limit, false, path, range, stoponcopy);
            XDoc ret    = new XDoc("html");

            ret.Start("body")
            .Start("div").Attr("class", "DW-table SVN-table table")
            .Start("table").Attr("border", 0).Attr("cellspacing", 0).Attr("cellpadding", 0).Attr("class", "table");

            // header
            ret.Start("tr")
            .Elem("th", "Revision")
            .Elem("th", "Date")
            .Elem("th", "Author")
            .Elem("th", "Message")
            .End();
            int count = 0;

            foreach (XDoc revision in svnRet["logentry"])
            {
                string msg = revision["msg"].AsText ?? string.Empty;
                msg = msg.Trim();
                string tdClass = count % 2 == 0 ? "bg1" : "bg2";
                if (!(verbose ?? false))
                {
                    //Trim the msg at a work boundary
                    int linebreak = StringUtil.IndexOfInvariantIgnoreCase(msg, "\n");
                    int cutoff;
                    if (linebreak > 0)
                    {
                        cutoff = Math.Min(linebreak, DEFAULT_LIMIT);
                    }
                    else
                    {
                        cutoff = DEFAULT_LIMIT;
                    }
                    while (msg.Length > cutoff && cutoff - DEFAULT_MSG_LENGTH <= 10)
                    {
                        if (char.IsWhiteSpace(msg[cutoff]))
                        {
                            break;
                        }
                        cutoff++;
                    }

                    if (msg.Length > cutoff)
                    {
                        msg = string.Format("{0} …", msg.Substring(0, Math.Min(msg.Length - 1, cutoff)));
                    }
                }

                DateTime d    = revision["date"].AsDate ?? DateTime.MinValue;
                string   date = d.ToString(DreamContext.Current.Culture);
                ret.Start("tr");
                ret.Start("td").Attr("class", tdClass);
                OutputRevLink(ret, revision["@revision"].AsText).End();
                ret.Start("td").Attr("class", tdClass).Value(date).End();
                ret.Start("td").Attr("class", tdClass).Value(revision["author"].AsText).End();
                ret.Start("td").Attr("class", tdClass);
                ParseRevMessage(ret, msg).End();
                ret.End();//tr

                count++;
            }

            ret.End(); //body
            ret.End(); //table
            ret.End(); //div

            return(ret);
        }