//--- 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; }
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; }
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; }
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(); } }
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(); } }
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(); } }
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; }
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; }
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; }
//--- 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; }
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()); }
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 + "\""); } }
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; }
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; }
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"); }
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; }
//--- 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; }
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; }
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; }
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; }
/// <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; }
//--- 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(); }
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(); } }
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; }
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; }
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; }
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; }
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(); }
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); }