public Yield GetInfo(DreamContext aContext, DreamMessage aRequest, Result<DreamMessage> aResponse) { XDoc xmlInfo = new XDoc("info"); xmlInfo.Elem("User", Context.Current.User); xmlInfo.Elem("About", "Foiremuses web service (c) 2011 Vincent DARON / Danny WILLEM"); aResponse.Return(DreamMessage.Ok(MimeType.XML, xmlInfo)); yield break; }
//--- 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; }
public void TestFullServiceLifetime() { Plug p = Utils.BuildPlugForAdmin(); string desc = "test service"; XDoc serviceXml = new XDoc("service"); serviceXml.Elem("sid", TEST_SERVICE_SID); serviceXml.Elem("type", "ext"); serviceXml.Elem("description", desc); serviceXml.Elem("init", "native"); //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); //todo: validate the service //start the service msg = p.At("site", "services", service_id.ToString(), "start").PostAsync().Wait(); Assert.IsTrue(msg.IsSuccessful, "service startup failed"); XUri uri = msg.ToDocument()["uri"].AsUri; Assert.IsNotNull(uri); Assert.IsTrue(!string.IsNullOrEmpty(uri.ToString())); //stop the service msg = p.At("site", "services", service_id.ToString(), "stop").PostAsync().Wait(); Assert.IsTrue(msg.IsSuccessful, "service stopping failed"); Assert.IsTrue(string.IsNullOrEmpty(msg.ToDocument()["uri"].AsText)); msg = p.At("site", "services", service_id.ToString()).GetAsync().Wait(); Assert.IsTrue(msg.IsSuccessful); serviceXml = msg.ToDocument(); //start the service msg = p.At("site", "services", service_id.ToString(), "start").PostAsync().Wait(); Assert.IsTrue(msg.IsSuccessful, "service startup failed"); uri = msg.ToDocument()["uri"].AsUri; Assert.IsNotNull(uri); Assert.IsTrue(!string.IsNullOrEmpty(uri.ToString())); //start the service msg = p.At("site", "services", service_id.ToString(), "start").PostAsync().Wait(); Assert.IsTrue(msg.IsSuccessful, "service refresh failed"); uri = msg.ToDocument()["uri"].AsUri; Assert.IsNotNull(uri); Assert.IsTrue(!string.IsNullOrEmpty(uri.ToString())); //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.AreEqual(DreamStatus.NotFound, msg.Status, "service still exists after deletion"); }
//--- Class Methods --- private static XDoc AddTableStyles(XDoc doc) { XDoc head = doc["head"]; if(head.IsEmpty) { doc.Elem("head"); head = doc["head"]; } head.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(); return doc; }
public void Can_provide_list_of_args_as_repeated_params_to_feature() { MockServiceInfo mock = MockService.CreateMockService(_hostInfo); mock.Service.CatchAllCallback = delegate(DreamContext context, DreamMessage request, Result<DreamMessage> response2) { XDoc msg = new XDoc("ids"); foreach(KeyValuePair<string, string> kv in context.GetParams()) { if(kv.Key == "id") { msg.Elem("id", kv.Value); } } response2.Return(DreamMessage.Ok(msg)); }; Plug p = mock.AtLocalHost; int n = 100; List<string> ids = new List<string>(); for(int i = 0; i < n; i++) { p = p.With("id", i); ids.Add(i.ToString()); } DreamMessage result = p.GetAsync().Wait(); Assert.IsTrue(result.IsSuccessful); List<string> seen = new List<string>(); foreach(XDoc id in result.ToDocument()["id"]) { string v = id.AsText; Assert.Contains(v, ids); Assert.IsFalse(seen.Contains(v)); seen.Add(v); } Assert.AreEqual(ids.Count, seen.Count); }
public Yield GetSearchDescription(DreamContext context, DreamMessage request, Result<DreamMessage> response) { XDoc description = new XDoc("OpenSearchDescription", "http://a9.com/-/spec/opensearch/1.1/"); description.Elem("ShortName", string.Format(DekiResources.OPENSEARCH_SHORTNAME, DekiContext.Current.Instance.SiteName)) .Elem("Description", DekiResources.OPENSEARCH_DESCRIPTION) .Start("Query") .Attr("role", "example") .Attr("searchTerms", "Wiki") .End(); // HACK HACK HACK: we can't use XUri because it encodes the "{}" characters string uri = DekiContext.Current.ApiUri.At("site", "opensearch").ToString(); uri += "?q={searchTerms}&offset={startIndex}&limit={count?}&"; description.Start("Url") .Attr("type", "text/html") .Attr("indexOffset", 0) .Attr("template", DekiContext.Current.UiUri.At("Special:Search").ToString() + "?search={searchTerms}&offset=0&limit={count?}&format=html") .End() .Start("Url") .Attr("type", "application/atom+xml") .Attr("indexOffset", 0) .Attr("template", uri + "format=atom") .End() .Start("Url") .Attr("type", "application/rss+xml") .Attr("indexOffset", 0) .Attr("template", uri + "format=rss") .End() .Start("Url") .Attr("type", "application/x-suggestions+json") .Attr("template", DekiContext.Current.ApiUri.At("site", "opensearch", "suggestions").ToString() + "?q={searchTerms}") .End(); response.Return(DreamMessage.Ok(description)); yield break; }
//--- Methods --- public XDoc ToXml(XUri uri) { XDoc result = new XDoc("function"); result.Attr("transform", Transform); if(IsProperty) { result.Attr("usage", "property"); } result.Elem("name", Name); result.Elem("uri", uri); result.Elem("description", Description); if(Access != DreamAccess.Public) { result.Elem("access", Access.ToString().ToLowerInvariant()); } foreach(DekiScriptParameter param in Parameters) { param.AppendXml(result); } result.Start("return").Attr("type", DekiScriptLiteral.AsScriptTypeName(ReturnType)).End(); return result; }
//--- Methods --- public XDoc ToXml() { XDoc result = new XDoc("group"); result.Attr("name", Name); if(HasCustom) { foreach(KeyValuePair<string, string> custom in ArrayUtil.AllKeyValues(Custom)) { result.Elem(custom.Key, custom.Value); } } return result; }
//--- Class Methods --- private static void Main(string[] args) { Plug host = null; try { // create the dream environment XDoc dreamConfigDoc = new XDoc("config"); dreamConfigDoc.Elem("server-name", MKS_PATH); dreamConfigDoc.Elem("service-dir", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); dreamConfigDoc.Elem("apikey", API_KEY); host = (new DreamHost(dreamConfigDoc)).Self.With("apikey", API_KEY); host.At("load").With("name", "mindtouch.deki.mwconverter").Post(); host.At("load").With("name", "mindtouch.deki").Post(); host.At("load").With("name", "mindtouch.indexservice").Post(); host.At("load").With("name", "mindtouch.deki.services").Post(); } catch (Exception e) { Console.WriteLine("An unexpected error occurred while creating the dream host."); Console.WriteLine(e); Environment.Exit(1); } try { // load the configuration information XDoc converterConfigDoc = XDocFactory.LoadFrom(CONFIG_FILE, MimeType.XML); XDoc dekiConfigDoc = XDocFactory.LoadFrom(converterConfigDoc["//deki/startup-xml"].Contents, MimeType.XML)["//config"]; dekiConfigDoc["path"].ReplaceValue("converter"); dekiConfigDoc["sid"].ReplaceValue("http://services.mindtouch.com/deki/internal/2007/12/mediawiki-converter"); dekiConfigDoc.Add(converterConfigDoc["//mediawiki"]); host.At("services").Post(dekiConfigDoc); } catch (Exception e) { Console.WriteLine("An unexpected error occurred while loading the converter configuration settings."); Console.WriteLine(e); Environment.Exit(1); } Plug service = Plug.New(host.Uri.AtAbsolutePath("converter"), TimeSpan.MaxValue); service.PostAsync(); Console.ReadLine(); }
protected override XDoc GetConfigForWikiId(string wikiId) { string configXpath = string.Format("wikis/config[@id='{0}']", wikiId); XDoc instanceConfig = _dekiService.Config[configXpath]; if (instanceConfig.IsEmpty && wikiId == DEFAULT_WIKI_ID && _dekiService.Config["wikis"].IsEmpty) { // For backwards compatibility with older style config doc, just extract the db settings from the service startup xml. // All other settings are either environmental(service-wide) or in the config table. instanceConfig = new XDoc("config"); foreach (string s in new string[] { "db-server", "db-port", "db-catalog", "db-user", "db-password", "db-options" }) { instanceConfig.Elem(s, _dekiService.Config[s].AsText); } } return instanceConfig; }
public static XDoc DekiScriptToXmlRpc(string function, DekiScriptLiteral arguments) { XDoc xdoc = new XDoc("methodCall"); xdoc.Elem("methodName", function); if (arguments.ScriptType.Equals(DekiScriptType.LIST)) { XmlRpcLiteralRecurse(xdoc, arguments, true); } else { xdoc.Start("params").Start("param"); XmlRpcLiteralRecurse(xdoc, arguments, false); xdoc.End().End(); } return(xdoc); }
protected override XDoc GetConfigForWikiId(string wikiId) { string configXpath = string.Format("wikis/config[@id='{0}']", wikiId); XDoc instanceConfig = _dekiService.Config[configXpath]; if (instanceConfig.IsEmpty && wikiId == DEFAULT_WIKI_ID && _dekiService.Config["wikis"].IsEmpty) { // For backwards compatibility with older style config doc, just extract the db settings from the service startup xml. // All other settings are either environmental(service-wide) or in the config table. instanceConfig = new XDoc("config"); foreach (string s in new string[] { "db-server", "db-port", "db-catalog", "db-user", "db-password", "db-options" }) { instanceConfig.Elem(s, _dekiService.Config[s].AsText); } } return(instanceConfig); }
/// <summary> /// Execute command and read result into an XDoc. /// </summary> /// <param name="table">Name of the root element</param> /// <param name="row">Name of the element created for each row</param> /// <returns>Read DataSet object</returns> public XDoc ReadAsXDoc(string table, string row) { _log.TraceMethodCall("ReadAsXDoc()", _command.CommandText); XDoc result = new XDoc(table); Execute(delegate(IDataReader reader) { // capture row columns int count = reader.FieldCount; string[] columns = new string[count]; bool[] attr = new bool[count]; for (int i = 0; i < count; ++i) { columns[i] = reader.GetName(i); if (columns[i].StartsWith("@")) { attr[i] = true; columns[i] = columns[i].Substring(1); } } // read records while (reader.Read()) { result.Start(row); for (int i = 0; i < count; ++i) { if (!reader.IsDBNull(i)) { string column = columns[i]; if (attr[0]) { result.Attr(column, reader.GetValue(i).ToString()); } else { result.Elem(column, reader.GetValue(i).ToString()); } } } result.End(); } }); return(result); }
public static XDoc GetUserMetricsXml(UserBE user) { var metrics = DbUtils.CurrentSession.Users_GetUserMetrics(user.ID); var ret = new XDoc("metrics"); ret.Attr("user.id", user.ID); ret.Attr("href", DekiContext.Current.ApiUri.At("users", user.ID.ToString(), "metrics")); ret.Elem("metric.comments", metrics.CommentPosts); ret.Elem("metric.pages-created", metrics.PagesCreated); ret.Elem("metric.pages-edited", metrics.PagesChanged); ret.Elem("metric.files-added", metrics.FilesUploaded); ret.Elem("metric.ratings-up", metrics.UpRatings); ret.Elem("metric.ratings-down", metrics.DownRatings); return(ret); }
public Yield PostRun(DreamContext context, DreamMessage request, Result <DreamMessage> response) { XDoc doc = request.ToDocument(); string name = doc["dappName"].AsText; XUri input = doc["applyToUrl"].AsUri; string xpath = doc["xpath"].AsText; // convert args Hashtable args = new Hashtable(); foreach (XDoc item in doc.Elements) { if (StringUtil.StartsWithInvariant(item.Name, VARIABLE_PREFIX)) { args[item.Name.Substring(VARIABLE_PREFIX.Length)] = item.AsText; } } // invoke dapper Result <XDoc> res; yield return(res = Coroutine.Invoke(FetchResult, name, input, args, new Result <XDoc>())); // create result document XDoc rows = res.Value[xpath ?? ".//*[@type='group']"]; XDoc result = new XDoc("results"); foreach (XDoc row in rows) { result.Start("result"); foreach (XDoc cell in row.Elements) { result.Elem(cell.Name, cell.AsText); } result.End(); } string json = JsonUtil.ToJson(result); response.Return(DreamMessage.Ok(MimeType.JSON, json)); yield break; }
/// <summary> /// Builds a http://sitemaps.org compliant sitemap as used by google (https://www.google.com/webmasters/tools/docs/en/protocol.html) /// </summary> /// <param name="rootPage"></param> /// <returns></returns> public static XDoc BuildGoogleSiteMap(PageBE rootPage, string language) { IList <PageBE> pages = null; Dictionary <ulong, IList <ulong> > childrenInfo = null; DbUtils.CurrentSession.Pages_GetDescendants(rootPage, null, true, out pages, out childrenInfo, ConfigBL.GetInstanceSettingsValueAs <int>(ConfigBL.MAX_SITEMAP_SIZE_KEY, ConfigBL.MAX_SITEMAP_SIZE)); PageBE[] allowedPages = PermissionsBL.FilterDisallowed(DekiContext.Current.User, pages, false, new Permissions[] { Permissions.BROWSE }); Dictionary <ulong, PageBE> allowedPagesById = allowedPages.AsHash(e => e.ID); Dictionary <ulong, PageBE> addedPagesById = null; if (!string.IsNullOrEmpty(language)) { List <ulong> pagesToRemove = new List <ulong>(); foreach (KeyValuePair <ulong, PageBE> page in allowedPagesById) { if (!string.IsNullOrEmpty(page.Value.Language) && !StringUtil.EqualsInvariantIgnoreCase(page.Value.Language, language)) { pagesToRemove.Add(page.Key); } } foreach (ulong pageId in pagesToRemove) { allowedPagesById.Remove(pageId); } } PageBL.AddParentsOfAllowedChildren(rootPage, allowedPagesById, addedPagesById); XDoc x = new XDoc("urlset", "http://www.google.com/schemas/sitemap/0.84"); foreach (PageBE p in allowedPagesById.Values) { x.Start("url"); x.Elem("loc", Utils.AsPublicUiUri(p.Title)); x.Start("lastmod").Value(p.TimeStamp.ToString("yyyy-MM-dd")).End(); x.End(); } return(x); }
public void Can_provide_list_of_args_as_repeated_params_to_feature() { MockServiceInfo mock = MockService.CreateMockService(_hostInfo); mock.Service.CatchAllCallback = delegate(DreamContext context, DreamMessage request, Result <DreamMessage> response2) { XDoc msg = new XDoc("ids"); foreach (KeyValuePair <string, string> kv in context.GetParams()) { if (kv.Key == "id") { msg.Elem("id", kv.Value); } } response2.Return(DreamMessage.Ok(msg)); }; Plug p = mock.AtLocalHost; int n = 100; List <string> ids = new List <string>(); for (int i = 0; i < n; i++) { p = p.With("id", i); ids.Add(i.ToString()); } DreamMessage result = p.GetAsync().Wait(); Assert.IsTrue(result.IsSuccessful); List <string> seen = new List <string>(); foreach (XDoc id in result.ToDocument()["id"]) { string v = id.AsText; Assert.Contains(v, ids); Assert.IsFalse(seen.Contains(v)); seen.Add(v); } Assert.AreEqual(ids.Count, seen.Count); }
public static DreamMessage BuildDeletedPageContents(uint pageid) { ArchiveBE page = DbUtils.CurrentSession.Archive_GetPageHeadById(pageid); if (page == null) { throw new DreamAbortException(DreamMessage.NotFound(string.Format(DekiResources.RESTORE_PAGE_ID_NOT_FOUND, pageid))); } //HACKHACKHACK MaxM: Copy data to a PageBE object since parser will not work on an ArchiveBE. ArchiveBE needs to go away. PageBE tempP = new PageBE(); tempP.Title = page.Title; tempP.SetText(page.Text); tempP.ContentType = page.ContentType; ParserResult parserResult = DekiXmlParser.Parse(tempP, ParserMode.VIEW_NO_EXECUTE); // TODO (steveb): this code is almost identical to the one in "GET:pages/{pageid}/contents"; consider merging // post process tail DekiXmlParser.PostProcessParserResults(parserResult); // wrap the result in a content tag and return it to the user XDoc result = new XDoc("content").Attr("type", parserResult.ContentType); foreach (XDoc entry in parserResult.Content.Elements) { if (entry.HasName("body")) { result.Start("body").Attr("target", entry["@target"].AsText).Value(entry.ToInnerXHtml()).End(); } else { result.Elem(entry.Name, entry.ToInnerXHtml()); } } // check if we hit a snag, which is indicated by a plain-text response if ((parserResult.ContentType == MimeType.TEXT.FullType) && (page.ContentType != MimeType.TEXT.FullType)) { // something happened during parsing return new DreamMessage(DreamStatus.NonAuthoritativeInformation, null, result); } else { return DreamMessage.Ok(result); } }
private Yield ConfigureMailer(XDoc settings, Result result) { var instance = DekiContext.Current.Instance; XDoc config = null; if (!string.IsNullOrEmpty(settings["mail/smtp-servers"].AsText)) { var port = settings["mail/smtp-port"].AsText; config = new XDoc("smtp") .Elem("smtp-host", settings["mail/smtp-servers"].AsText) .Elem("use-ssl", (settings["mail/smtp-secure"].AsText ?? string.Empty).EndsWithInvariantIgnoreCase("ssl") || (settings["mail/smtp-secure"].AsText ?? string.Empty).EndsWithInvariantIgnoreCase("tls")) .Elem("smtp-port", string.IsNullOrEmpty(port) ? null : port) .Elem("smtp-auth-user", settings["mail/smtp-username"].AsText) .Elem("smtp-auth-password", settings["mail/smtp-password"].AsText); if (!string.IsNullOrEmpty(instance.ApiKey)) { config.Elem("apikey", instance.ApiKey); } } if (config == null && !string.IsNullOrEmpty(instance.ApiKey)) { config = new XDoc("config") .Elem("apikey", instance.ApiKey) .AddAll(Config["smtp/*"]); } if (config == null) { yield return(Mailer.At("configuration", instance.Id).DeleteAsync()); } else { yield return(Mailer.At("configuration", instance.Id).PutAsync(config)); } result.Return(); yield break; }
public void ToXml(XDoc parent) { parent .Start("function") .Elem("name", Name); if (!string.IsNullOrEmpty(_access)) { parent.Elem("access", _access); } foreach (var parameter in _parameters) { parent .Start("param") .Attr("name", parameter.Key) .Attr("type", parameter.Value.Type); if (!string.IsNullOrEmpty(parameter.Value.Default)) { parent.Attr("default", parameter.Value.Default); } parent.End(); } parent .Start("return") .Attr("type", _type); if (_htmlBody != null) { parent.AddAll(_htmlBody); } else { parent.Value(_body); } parent .End() .End(); }
public Yield GetExtensionLibrary(DreamContext contex, DreamMessage request, Result <DreamMessage> response) { // create manifest XDoc manifest = new XDoc("extension"); manifest.Elem("title", _title); manifest.Elem("label", _label); manifest.Elem("copyright", _copyright); manifest.Elem("description", _description); manifest.Elem("uri.help", _help); manifest.Elem("uri.logo", _logo); manifest.Elem("namespace", _namespace); // add functions foreach (var function in _functions) { if (function.Value.Access == DreamAccess.Public) { manifest.Add(function.Value.ToXml(function.Key)); } } response.Return(DreamMessage.Ok(manifest)); yield break; }
protected override Yield Start(XDoc config, IContainer container, Result result) { yield return(Coroutine.Invoke(base.Start, config, new Result())); // ensure imagemagick is setup correctly. if (string.IsNullOrEmpty(ImageMagickConvertPath)) { throw new NotImplementedException("Please set 'imagemagick-convert-path' in config to path of ImageMagick's 'convert'"); } if (!File.Exists(ImageMagickIdentifyPath)) { throw new FileNotFoundException("Cannot find ImagicMagick 'identify' binary: ", ImageMagickIdentifyPath); } if (string.IsNullOrEmpty(ImageMagickIdentifyPath)) { throw new NotImplementedException("Please set 'imagemagick-identify-path' in config to path of ImageMagick's 'identify'"); } if (!File.Exists(ImageMagickConvertPath)) { throw new FileNotFoundException("Cannot find ImagicMagick 'convert' binary: ", ImageMagickConvertPath); } // check for 'apikey' _apikey = Config["api-key"].AsText ?? Config["apikey"].AsText; if (string.IsNullOrEmpty(_apikey)) { throw new ArgumentNullException("apikey", "The global apikey is not defined. Please ensure that you have a global <apikey> defined in the MindTouch Core service settings xml file."); } InitializeContainer(container); // intialize instance manager _instanceManager = InstanceManager.New(this, this.TimerFactory); // setup resource manager lock (SyncRoot) { if (ResourceManager == null) { ResourceManager = new PlainTextResourceManager(ResourcesPath); ScreenFont = new DekiFont(Plug.New("resource://mindtouch.deki/MindTouch.Deki.Resources.Arial.mtdf").Get().AsBytes()); } } // initialize scripting engine XDoc scripting = Config["scripting"]; DekiScriptLibrary.InsertTextLimit = scripting["max-web-response-length"].AsLong ?? DekiScriptLibrary.InsertTextLimit; DekiScriptLibrary.MinCacheTtl = scripting["min-web-cache-ttl"].AsDouble ?? DekiScriptLibrary.MinCacheTtl; // set up deki pub sub (by default we override uri.publish with our own service, unless @must-use=true is specified) if (!(Config["uri.publish/@must-use"].AsBool ?? false)) { Result <Plug> pubsubResult; XDoc pubsubConfig = new XDoc("config") .Elem("uri.deki", Self.Uri.With("apikey", MasterApiKey)) .Start("downstream") .Elem("uri", PubSub.At("publish").Uri.WithoutLastSegment().At("subscribers")) .End() .Start("components") .Start("component") .Attr("type", typeof(IPubSubDispatcher).AssemblyQualifiedName) .Attr("implementation", typeof(DekiDispatcher).AssemblyQualifiedName) .End() .End() .Elem("authtoken", MasterApiKey); foreach (var cookie in Cookies.Fetch(PubSub.Uri)) { pubsubConfig.Add(cookie.AsSetCookieDocument); } var messageQueuePath = config["publish/queue-path"].AsText; if (!string.IsNullOrEmpty(messageQueuePath)) { pubsubConfig.Elem("queue-path", messageQueuePath); } yield return(pubsubResult = CreateService( "pubsub", "sid://mindtouch.com/dream/2008/10/pubsub", pubsubConfig, new Result <Plug>())); PubSub = pubsubResult.Value; } // set up package updater service (unless it was passed in) XUri packageUpdater; if (config["packageupdater/@uri"].IsEmpty) { var packageConfig = config["packageupdater"]; packageConfig = packageConfig.IsEmpty ? new XDoc("config") : packageConfig.Clone(); if (packageConfig["package-path"].IsEmpty) { packageConfig.Elem("package-path", Path.Combine(Path.Combine(config["deki-path"].AsText, "packages"), "default")); } yield return(CreateService( "packageupdater", "sid://mindtouch.com/2010/04/packageupdater", new XDoc("config") .Elem("apikey", MasterApiKey) .AddNodes(packageConfig), new Result <Plug>() )); packageUpdater = Self.Uri.At("packageupdater"); } else { packageUpdater = config["packageupdater/@uri"].AsUri; } _packageUpdater = Plug.New(packageUpdater); // set up emailer service (unless it was passed in) XUri mailerUri; if (config["uri.mailer"].IsEmpty) { yield return(CreateService( "mailer", "sid://mindtouch.com/2009/01/dream/email", new XDoc("config") .Elem("apikey", MasterApiKey) .AddAll(Config["smtp/*"]), new Result <Plug>() )); mailerUri = Self.Uri.At("mailer"); } else { mailerUri = config["uri.mailer"].AsUri; } _mailer = Plug.New(mailerUri); // set up the email subscription service (unless it was passed in) XUri pageSubscription; if (config["uri.page-subscription"].IsEmpty) { XDoc pagesubserviceConfig = new XDoc("config") .Elem("uri.deki", Self.Uri) .Elem("uri.emailer", mailerUri.At("message")) .Elem("resources-path", ResourcesPath) .Elem("apikey", MasterApiKey) .Start("components") .Start("component") .Attr("scope", "factory") .Attr("type", typeof(IPageSubscriptionDataSessionFactory).AssemblyQualifiedName) .Attr("implementation", "MindTouch.Deki.Data.MySql.UserSubscription.MySqlPageSubscriptionSessionFactory, mindtouch.deki.data.mysql") .End() .End() .AddAll(Config["page-subscription/*"]); foreach (var cookie in Cookies.Fetch(mailerUri)) { pagesubserviceConfig.Add(cookie.AsSetCookieDocument); } yield return(CreateService( "pagesubservice", "sid://mindtouch.com/deki/2008/11/changesubscription", pagesubserviceConfig, new Result <Plug>() )); pageSubscription = Self.Uri.At("pagesubservice"); config.Elem("uri.page-subscription", pageSubscription); } else { pageSubscription = config["uri.page-subscription"].AsUri; } _pageSubscription = Plug.New(pageSubscription); // set up package importer, if not provided if (Config["uri.package"].IsEmpty) { yield return(CreateService( "package", "sid://mindtouch.com/2009/07/package", new XDoc("config").Elem("uri.deki", Self.Uri), new Result <Plug>())); Config.Elem("uri.package", Self.Uri.At("package")); } // set up lucene _luceneIndex = Plug.New(Config["indexer/@src"].AsUri); if (_luceneIndex == null) { // create the indexer service XDoc luceneIndexConfig = new XDoc("config") .AddNodes(Config["indexer"]) .Start("apikey").Attr("hidden", true).Value(MasterApiKey).End(); if (luceneIndexConfig["path.store"].IsEmpty) { luceneIndexConfig.Elem("path.store", Path.Combine(Path.Combine(config["deki-path"].AsText, "luceneindex"), "$1")); } yield return(CreateService("luceneindex", SID_FOR_LUCENE_INDEX, luceneIndexConfig, new Result <Plug>()).Set(v => _luceneIndex = v)); _isLocalLuceneService = true; } else { // push our host's pubsub service to lucene, to keep it up to date on our changes var pubsub = new XDoc("pubsub").Attr("href", PubSub); foreach (var cookie in PubSub.CookieJar.Fetch(PubSub.Uri)) { pubsub.Add(cookie.AsSetCookieDocument); } yield return(_luceneIndex.At("subscriptions").PostAsync(pubsub)); } // configure indexing whitelist _indexNamespaceWhitelist = new[] { NS.MAIN, NS.PROJECT, NS.USER, NS.TEMPLATE, NS.HELP, NS.MAIN_TALK, NS.PROJECT_TALK, NS.USER_TALK, NS.TEMPLATE_TALK, NS.HELP_TALK, NS.SPECIAL, NS.SPECIAL_TALK }; if (!string.IsNullOrEmpty(Config["indexer/namespace-whitelist"].AsText)) { List <NS> customWhitelist = new List <NS>(); foreach (string item in Config["indexer/namespace-whitelist"].AsText.Split(',')) { NS ns; if (SysUtil.TryParseEnum(item, out ns)) { customWhitelist.Add(ns); } } _indexNamespaceWhitelist = customWhitelist.ToArray(); } if (!Config["wikis/globalconfig/cache/varnish"].IsEmpty) { // create the varnish service // TODO (petee): getting the varnish config from wikis/globalconfig/cache is a hack // The frontend needs to get the max-age to send out the cache headers but we currently have no way // of getting the DekiWikiService config so we'll hack it so it comes back in GET:site/settings. XDoc varnishConfig = new XDoc("config") .Elem("uri.deki", Self.Uri.With("apikey", MasterApiKey)) .Elem("uri.varnish", Config["wikis/globalconfig/cache/varnish"].AsUri) .Elem("varnish-purge-delay", Config["wikis/globalconfig/cache/varnish-purge-delay"].AsInt ?? 10) .Elem("varnish-max-age", Config["wikis/globalconfig/cache/varnish-max-age"].AsInt ?? 300) .Start("apikey").Attr("hidden", true).Value(MasterApiKey).End(); yield return(CreateService("varnish", SID_FOR_VARNISH_SERVICE, varnishConfig, new Result <Plug>())); } _isInitialized = true; result.Return(); }
public Yield GetSiteFunctions(DreamContext context, DreamMessage request, Result <DreamMessage> response) { if (UserBL.IsAnonymous(DekiContext.Current.User)) { throw new SiteMustBeLoggedInForbiddenException(); } // 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, "label", ExtensionBL.GetExtensionPreference(serviceUri, "label.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) { var resources = DekiContext.Current.Resources; var builder = new DekiResourceBuilder(); builder.Append(" ("); builder.Append(DekiResources.PROTECTED()); builder.Append(")"); result.Value(builder.Localize(resources)); } 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; }
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"); }
//--- Class Methods --- public static ServiceBE StartService(ServiceBE service, bool forceRefresh, bool disableOnFailure) { // create subordinate request id for service start var dreamContext = DreamContext.Current; var requestId = dreamContext.GetState<string>(DreamHeaders.DREAM_REQUEST_ID); dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId + "-service_" + service.Id); try { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); service.ServiceLastStatus = string.Empty; StopService(service.Id, service, ServiceStopType.Restart); DekiContext context = DekiContext.Current; bool dirtyServiceEntity = false; XUri location; ServiceRepository.IServiceInfo serviceInfo = null; try { // check if service is local if(service.ServiceLocal) { if(string.IsNullOrEmpty(service.SID)) { throw new Exception("missing SID"); } // start service if(IsLocalAuthService(service)) { // this service is the built-in authentication provider; no need to start it location = context.Deki.Self; } else { // convert local service configuration into an xdoc XDoc config = new XDoc("config"); foreach(KeyValuePair<string, string> configEntry in ArrayUtil.AllKeyValues(service.Config)) { config.InsertValueAt(configEntry.Key, configEntry.Value); } // if no apikey was provided, create a random one so that CreateService doesn't inject the parent one if(config["apikey"].IsEmpty) { config.Elem("apikey", StringUtil.CreateAlphaNumericKey(16)); } // add information for service to callback into deki if(config["uri.deki"].IsEmpty) { config.Elem("uri.deki", context.Deki.Self); config.Elem("wikiid.deki", context.Instance.Id); config.Elem("apikey.deki", context.Deki.MasterApiKey); } // the service location must use the service ID and the instance ID string servicePath = string.Format("services/{0}/{1}", context.Instance.Id, service.Id); serviceInfo = context.Instance.CreateLocalService(service, servicePath, config); location = serviceInfo.ServiceUri; } // check if the service uri has changed since last invocation (happens when service is started for the first time or server GUID has changed) if(!service.Uri.EqualsInvariantIgnoreCase(location.ToString())) { dirtyServiceEntity = true; service.Uri = location.ToString(); } } else { if(string.IsNullOrEmpty(service.Uri)) { throw new Exception("missing URI"); } location = new XUri(service.Uri); serviceInfo = context.Instance.RegisterRemoteService(service, location); } // check if service is an Extension service if(service.Type == ServiceType.EXT) { ExtensionBL.StartExtensionService(context, service, serviceInfo, forceRefresh); } //Successfully starting a service enables it. if(!service.ServiceEnabled) { dirtyServiceEntity = true; service.ServiceEnabled = true; } } catch(Exception e) { dirtyServiceEntity = true; DreamMessage dm = null; if(e is DreamResponseException) { dm = ((DreamResponseException)e).Response; string message = dm.HasDocument ? dm.ToDocument()[".//message"].AsText.IfNullOrEmpty(e.Message) : dm.ToText(); service.ServiceLastStatus = string.Format("unable to initialize service ({0})", message); } else { service.ServiceLastStatus = e.GetCoroutineStackTrace(); } if(serviceInfo != null) { try { context.Instance.DeregisterService(service.Id); } catch {} } // A service that fails to start becomes disabled if it's started explicitly (not during deki startup) if(disableOnFailure) { service.ServiceEnabled = false; } context.Instance.Log.ErrorExceptionMethodCall(e, "StartService", string.Format("Unable to start local service id '{0}' with SID '{1}' Error: '{2}'", service.Id, service.SID, service.ServiceLastStatus)); if(dm != null) { throw new DreamAbortException(dm); } else { throw; } } finally { // don't update remote services that haven't changed if(dirtyServiceEntity) { service = UpdateService(service); } } stopwatch.Stop(); _log.InfoFormat("Service '{0}' ({1}) started in {2}ms", service.Description, service.SID, stopwatch.ElapsedMilliseconds); return service; } finally { // restore the request id dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId); } }
private void AddOrReplace(XDoc doc, string key, string value) { if(value != null) { XDoc item = doc[key]; if(item.IsEmpty) { doc.Elem(key, value); } else { item.ReplaceValue(value); } } }
//--- Class Methods --- private static int Main(string[] args) { bool useTty = true; TimeSpan time; // process command line arguments XDoc config = new XDoc("config"); for (int i = 0; i < args.Length; i += 2) { string key = args[i].ToLowerInvariant(); string value = ((i + 1) < args.Length) ? args[i + 1] : string.Empty; switch (key) { case "help": PrintUsage(); return(0); case "notty": --i; useTty = false; break; case "capture-stack-trace": --i; DebugUtil.CaptureStackTrace = true; break; case "nolog": --i; // NOTE (steveb): this option used to disable logging, but was removed in favor of using the automatic re-reading of app.config by log4net break; case "settings": case "config": if (!File.Exists(value)) { WriteError(key, "config file not found"); return(1); } config = XDocFactory.LoadFrom(value, MimeType.XML); break; case "script": config.Start("script").Attr("src", value).End(); break; case "ip": case "host": config.Elem("host", value); break; case "http-port": case "path-prefix": case "server-path": case "server-name": case "storage-dir": case "connect-limit": case "apikey": case "guid": config.Elem(key, value); break; case "public-uri": case "root-uri": config.Elem("uri.public", value); break; case "service-dir": config.Elem("storage-dir", value); break; case "collect-interval": int interval; if (!int.TryParse(value, out interval)) { WriteError(key, "invalid collection interval (must be an integer representing seconds)"); return(1); } if (interval > 0) { DebugUtil.SetCollectionInterval(TimeSpan.FromSeconds(interval)); } break; case "auth": config.Elem("authentication-shemes", value); break; default: WriteError(key, "unknown setting"); return(1); } } try { // initialize environment if (config["apikey"].IsEmpty) { string apikey = StringUtil.CreateAlphaNumericKey(32); config.Elem("apikey", apikey); Console.WriteLine("Dream Host APIKEY: {0}", apikey); } Console.WriteLine("-------------------- initializing"); time = DebugUtil.Stopwatch(() => { _host = new DreamHost(config); }); Console.WriteLine("-------------------- initialized {0} secs", time.TotalSeconds); // execute scripts time = DebugUtil.Stopwatch(() => { _host.RunScripts(config, null); }); Console.WriteLine("-------------------- ready {0} secs", time.TotalSeconds); // for UNIX systems, let's also listen to SIGTERM if (SysUtil.IsUnix) { new Thread(SigTermHandler) { IsBackground = true }.Start(); } // check if we can use the console if (useTty) { int debuglevel = 0; // wait for user input then exit while (_host.IsRunning) { Thread.Sleep(250); #region Interactive Key Handler if (Console.KeyAvailable) { ConsoleKeyInfo key = Console.ReadKey(true); switch (key.Key) { case ConsoleKey.Q: case ConsoleKey.Escape: case ConsoleKey.Spacebar: Console.WriteLine("Shutting down"); return(0); case ConsoleKey.G: Console.WriteLine("Full garbage collection pass"); System.GC.Collect(); break; case ConsoleKey.C: Console.Clear(); break; case ConsoleKey.D: switch (++debuglevel) { default: debuglevel = 0; Threading.RendezVousEvent.CaptureTaskState = false; DebugUtil.CaptureStackTrace = false; Console.WriteLine("Debug capture: none"); break; case 1: Threading.RendezVousEvent.CaptureTaskState = true; DebugUtil.CaptureStackTrace = false; Console.WriteLine("Debug capture: task-state only"); break; case 2: Threading.RendezVousEvent.CaptureTaskState = true; DebugUtil.CaptureStackTrace = true; Console.WriteLine("Debug capture: task-state and stack-trace"); break; } break; case ConsoleKey.I: { Console.WriteLine("--- System Information ---"); // show memory Console.WriteLine("Allocated memory: {0}", GC.GetTotalMemory(false)); // show threads int workerThreads; int completionThreads; int dispatcherThreads; int backgroundThreads; AsyncUtil.GetAvailableThreads(out workerThreads, out completionThreads, out dispatcherThreads, out backgroundThreads); int maxWorkerThreads; int maxCompletionThreads; int maxDispatcherThreads; int maxBackgroundThreads; AsyncUtil.GetMaxThreads(out maxWorkerThreads, out maxCompletionThreads, out maxDispatcherThreads, out maxBackgroundThreads); Console.WriteLine("Thread-pool worker threads available: {0} (max: {1})", workerThreads, maxWorkerThreads); Console.WriteLine("Thread-pool completion threads available: {0} (max: {1})", completionThreads, maxCompletionThreads); Console.WriteLine("Dispatcher threads available: {0} (max: {1})", dispatcherThreads, maxDispatcherThreads); Console.WriteLine("Thread-pool background worker threads available: {0} (max: {1})", backgroundThreads, maxBackgroundThreads); // show pending/waiting timers var taskTimerStats = Tasking.TaskTimerFactory.GetStatistics(); Console.WriteLine("Pending timer objects: {0}", taskTimerStats.PendingTimers); Console.WriteLine("Queued timer objects: {0}", taskTimerStats.QueuedTimers); Console.WriteLine("Timer retries: {0}", taskTimerStats.Retries); // show activities var activities = _host.ActivityMessages; Console.WriteLine("Host activities: {0}", activities.Length); foreach (var activity in activities) { Console.WriteLine("* {0}: {1}", activity.Created.ToString(XDoc.RFC_DATETIME_FORMAT), activity.Description); } // show pending tasks Console.WriteLine("Pending rendez-vous events: {0}", Threading.RendezVousEvent.PendingCounter); Console.WriteLine("Pending results: {0}", AResult.PendingCounter); lock (Threading.RendezVousEvent.Pending) { int count = 0; foreach (var entry in Threading.RendezVousEvent.Pending.Values) { ++count; if (entry.Key != null) { var context = entry.Key.GetState <DreamContext>(); if (context != null) { Console.WriteLine("--- DreamContext for pending rendez-vous event #{0} ---", count); Console.WriteLine(context.Uri.ToString(false)); } } Console.WriteLine(); if (entry.Value != null) { Console.WriteLine("--- Stack trace for pending rendez-vous event #{0} ---", count); Console.WriteLine(entry.Value.ToString()); } } } Console.WriteLine("--------------------------"); } break; case ConsoleKey.H: Console.WriteLine("Help:"); Console.WriteLine(" Q - quit application"); Console.WriteLine(" ESC - quit application"); Console.WriteLine(" SPACE - quit application"); Console.WriteLine(" G - full garbage collection"); Console.WriteLine(" C - clear screen"); Console.WriteLine(" D - set debug capture level"); Console.WriteLine(" I - show system information (memory, threads, pending tasks)"); Console.WriteLine(" H - this help text"); break; } } #endregion } } else { _host.WaitUntilShutdown(); } } finally { Console.WriteLine("-------------------- shutting down"); TaskTimerFactory.ShutdownAll(); if (_host != null) { _host.Dispose(); } } return(0); }
public static XDoc WebToggle( [DekiScriptParam("content to toggle")] XDoc content, [DekiScriptParam("title to display for toggle (default: \"Show\")", true)] string title, [DekiScriptParam("heading level for title (default: 3)", true)] int?heading, [DekiScriptParam("content toggle speed (one of \"slow\", \"normal\", \"fast\" or milliseconds number; default: instantaneous)", true)] string speed, [DekiScriptParam("hide content initially (default: true)", true)] bool?hidden ) { if (!content["body[not(@target)]"].IsEmpty) { string id = StringUtil.CreateAlphaNumericKey(8); // clone content so we don't modify the original content = content.Clone(); XDoc body = content["body[not(@target)]"]; // add <style> element XDoc head = content["head"]; if (head.IsEmpty) { content.Elem("head"); head = content["head"]; } head.Elem("style", @"h1.web-expand, h2.web-expand, h3.web-expand, h4.web-expand, h5.web-expand, h6.web-expand { cursor: pointer; } .web-expand span.web-expander { padding-right: 20px; background: transparent url('/skins/common/images/nav-parent-open.gif') no-repeat center right; } .web-expanded span.web-expander { background: transparent url('/skins/common/images/nav-parent-docked.gif') no-repeat center right; }"); // set speed if (string.IsNullOrEmpty(speed)) { speed = string.Empty; } else { int millisec; if (int.TryParse(speed, out millisec)) { speed = millisec.ToString(); } else { speed = "'" + speed + "'"; } } // create toggelable content bool hide = hidden ?? true; content .Start("body") .Start("h" + Math.Max(1, Math.Min(heading ?? 3, 6))) .Attr("class", "web-expand" + (hide ? string.Empty : " web-expanded")) .Attr("onclick", "$(this).toggleClass('web-expanded').next('#" + id + "').toggle(" + speed + ")") .Start("span") .Attr("class", "web-expander") .Value(title ?? "Show") .End() .End() .Start("div") .Attr("id", id) .Attr("style", hide ? "display: none;" : string.Empty) .AddNodes(body) .End() .End(); body.Remove(); } return(content); }
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; }
private void MovePermissions(ACConverterPageInfo pageInfo) { RemotePermission[] pagePermissions = _confluenceService.GetPagePermissions(pageInfo.ConfluencePage.id); //Change permissions list according to parent page permissoins List <RemotePermission> newPermissions = new List <RemotePermission>(); foreach (RemotePermission permission in pageInfo.ConfluenceUsersWithViewPermissions.Values) { newPermissions.Add(permission); } foreach (RemotePermission permission in pagePermissions) { if (permission.lockType == ConfluenceEditPermissionName) { if ((pageInfo.ConfluenceUsersWithViewPermissions.Count == 0) || (pageInfo.ConfluenceUsersWithViewPermissions.ContainsKey(permission.lockedBy.ToLower()))) { newPermissions.Add(permission); } } } pagePermissions = newPermissions.ToArray(); if (pagePermissions.Length == 0) { return; } string dekiRestriction; //Possible two entry of one user or group in pagePermissions. //As View permission and as Edit permission for this group/user. //To prevent repeated addition to Deki in this dictionary stored true //if permission to this user/group added to Deki. Dictionary <string, bool> permissionAddedToDeki = new Dictionary <string, bool>(); Dictionary <string, bool> userHaveWritePermission = new Dictionary <string, bool>(); if (_compatibleConvertUserPermissions) { bool onlyWriteRestrictions = true; foreach (RemotePermission permission in pagePermissions) { if (permission.lockType == ConfluenceViewPermissionName) { onlyWriteRestrictions = false; break; } } if (onlyWriteRestrictions) { //If there no view restrictions on this Confluence page set Semi-Public restrictions to Deki users dekiRestriction = "Semi-Public"; } else { //If there is view restrictions on this Confluence page to allow users/groups with View and Edit //restrictions view this page set Private restriction in Deki. //Users without Edit permission but with View permission in Confluence can edit this page in Deki. dekiRestriction = "Private"; } } else { dekiRestriction = "Private"; foreach (RemotePermission permission in pagePermissions) { if (permission.lockType == ConfluenceEditPermissionName) { userHaveWritePermission[permission.lockedBy.ToLower()] = true; } else { if (!userHaveWritePermission.ContainsKey(permission.lockedBy.ToLower())) { userHaveWritePermission[permission.lockedBy.ToLower()] = false; } } } } XDoc securityDoc = new XDoc("security") .Start("permissions.page") .Elem("restriction", dekiRestriction) .End() .Start("grants"); foreach (RemotePermission permission in pagePermissions) { if (permissionAddedToDeki.ContainsKey(permission.lockedBy.ToLower())) { continue; } securityDoc .Start("grant") .Start("permissions"); if (_compatibleConvertUserPermissions) { securityDoc.Elem("role", "Contributor"); } else { bool haveWritePermission = false; userHaveWritePermission.TryGetValue(permission.lockedBy.ToLower(), out haveWritePermission); if (haveWritePermission) { securityDoc.Elem("role", "Contributor"); } else { securityDoc.Elem("role", "Viewer"); } } securityDoc.End(); //Detect if this is group or user permission ACConverterUserInfo dekiUser; if (_convertedUsers.TryGetValue(permission.lockedBy.ToLower(), out dekiUser)) { securityDoc.Start("user").Attr("id", dekiUser.DekiUserId).End(); } else { ACConverterGroupInfo dekiGroup = null; if (_convertedGroups.TryGetValue(permission.lockedBy.ToLower(), out dekiGroup)) { securityDoc.Start("group").Attr("id", dekiGroup.DekiGroupId).End(); } else { WriteLineToConsole("Page " + pageInfo.ConfluencePage.title + " locked by " + permission.lockedBy + " that is not a user and not a group. Restriction ignored."); } } securityDoc.End(); permissionAddedToDeki[permission.lockedBy.ToLower()] = true; } securityDoc.End(); DreamMessage res = _dekiPlug.At("pages", pageInfo.DekiPageId.ToString(), "security").PutAsync(securityDoc).Wait(); if (res.Status != DreamStatus.Ok) { WriteLineToLog("Error converting permissions"); WriteErrorResponse(res); WriteErrorRequest(securityDoc); } }
//--- 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(); }
/// <summary> /// Create a new host with provided configuration and an Inversion of Control container. /// </summary> /// <remarks> /// The IoC container is also injected into default activator, so that <see cref="IDreamService"/> instances /// can be resolved from the container. The host configuration is provided to the container as a typed parameter. /// </remarks> /// <param name="config">Host configuration.</param> /// <param name="container">IoC Container.</param> public DreamHost(XDoc config, IContainer container) { if (config == null) { throw new ArgumentNullException("config"); } // read host settings string appDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName); int limit = config["connect-limit"].AsInt ?? 0; int httpPort = config["http-port"].AsInt ?? DEFAULT_PORT; AuthenticationSchemes authenticationScheme = AuthenticationSchemes.Anonymous; string authShemes = config["authentication-shemes"].AsText; if (!String.IsNullOrEmpty(authShemes)) { try { authenticationScheme = (AuthenticationSchemes)Enum.Parse(typeof(AuthenticationSchemes), authShemes, true); } catch (Exception e) { _log.Warn(String.Format("invalid authetication scheme specified :{0}", authShemes), e); } } // get the authtoken for whitelisting dream.in.* query args _dreamInParamAuthtoken = config["dream.in.authtoken"].AsText; if (!string.IsNullOrEmpty(_dreamInParamAuthtoken)) { _log.Debug("Host is configured in dream.in param authorizing mode"); } // read ip-addresses var addresses = new List <string>(); foreach (XDoc ip in config["host|ip"]) { addresses.Add(ip.AsText); } if (addresses.Count == 0) { // if no addresses were supplied listen to all addresses.Add("*:" + httpPort); } // use default servername XUri publicUri = config["uri.public"].AsUri; if (publicUri == null) { // backwards compatibility publicUri = config["server-name"].AsUri; if (publicUri == null) { foreach (IPAddress addr in Dns.GetHostAddresses(Dns.GetHostName())) { if (addr.AddressFamily == AddressFamily.InterNetwork) { XUri.TryParse("http://" + addr, out publicUri); } } if (publicUri == null) { // failed to get an address out of dns, fall back to localhost XUri.TryParse("http://localhost", out publicUri); } } publicUri = publicUri.AtPath(config["server-path"].AsText ?? config["path-prefix"].AsText ?? string.Empty); } // create environment and initialize it _env = new DreamHostService(container); try { // initialize environment string apikey = config["apikey"].AsText ?? StringUtil.CreateAlphaNumericKey(32); XDoc serviceConfig = new XDoc("config"); var storageType = config["storage/@type"].AsText ?? "local"; if ("s3".EqualsInvariant(storageType)) { serviceConfig.Add(config["storage"]); } else { serviceConfig.Elem("storage-dir", config["storage-dir"].AsText ?? config["service-dir"].AsText ?? appDirectory); } serviceConfig.Elem("apikey", apikey); serviceConfig.Elem("uri.public", publicUri); serviceConfig.Elem("connect-limit", limit); serviceConfig.Elem("guid", config["guid"].AsText); serviceConfig.AddAll(config["components"]); var memorize = config["memorize-aliases"]; if (!memorize.IsEmpty) { serviceConfig.Elem("memorize-aliases", memorize.AsBool); } _env.Initialize(serviceConfig); // initialize host plug _host = _env.Self.With("apikey", apikey); // load assemblies in 'services' folder string servicesFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "services"); if (Directory.Exists(servicesFolder)) { // Note (arnec): Deprecated, but the suggested alternative really doesn't apply since we don't want to // load services into a separate appdomain. #pragma warning disable 618,612 AppDomain.CurrentDomain.AppendPrivatePath("services"); #pragma warning restore 618,612 foreach (string file in Directory.GetFiles(servicesFolder, "*.dll")) { // register assembly blueprints DreamMessage response = _host.At("load").With("name", Path.GetFileNameWithoutExtension(file)).Post(new Result <DreamMessage>(TimeSpan.MaxValue)).Wait(); if (!response.IsSuccessful) { _log.WarnFormat("DreamHost: ERROR: assembly '{0}' failed to load", file); } } } // add acccess-points AddListener(new XUri(String.Format("http://{0}:{1}/", "localhost", httpPort)), authenticationScheme); // check if user prescribed a set of IP addresses to use if (addresses != null) { // listen to custom addresses (don't use the supplied port info, we expect that to be part of the address) foreach (string address in addresses) { if (!StringUtil.EqualsInvariantIgnoreCase(address, "localhost")) { AddListener(new XUri(String.Format("http://{0}/", address)), authenticationScheme); } } } else { // add listeners for all known IP addresses foreach (IPAddress address in Dns.GetHostAddresses(Dns.GetHostName())) { XUri uri = MakeUri(address, httpPort); if (uri != null) { AddListener(uri, authenticationScheme); try { foreach (string alias in Dns.GetHostEntry(address).Aliases) { AddListener(new XUri(String.Format("http://{0}:{1}/", alias, httpPort)), authenticationScheme); } } catch { } } } } } catch (Exception e) { if ((e is HttpListenerException) && e.Message.EqualsInvariant("Access is denied")) { _log.ErrorExceptionMethodCall(e, "ctor", "insufficient privileges to create HttpListener, make sure the application runs with Administrator rights"); } else { _log.ErrorExceptionMethodCall(e, "ctor"); } try { _env.Deinitialize(); } catch { } throw; } }
//--- Class Methods --- private static int Main(string[] args) { bool useTty = true; TimeSpan time; // process command line arguments XDoc config = new XDoc("config"); for(int i = 0; i < args.Length; i += 2) { string key = args[i].ToLowerInvariant(); string value = ((i + 1) < args.Length) ? args[i + 1] : string.Empty; switch(key) { case "help": PrintUsage(); return 0; case "notty": --i; useTty = false; break; case "capture-stack-trace": --i; DebugUtil.CaptureStackTrace = true; break; case "nolog": --i; // NOTE (steveb): this option used to disable logging, but was removed in favor of using the automatic re-reading of app.config by log4net break; case "settings": case "config": if(!File.Exists(value)) { WriteError(key, "config file not found"); return 1; } config = XDocFactory.LoadFrom(value, MimeType.XML); break; case "script": config.Start("script").Attr("src", value).End(); break; case "ip": case "host": config.Elem("host", value); break; case "http-port": case "path-prefix": case "server-path": case "server-name": case "storage-dir": case "connect-limit": case "apikey": case "guid": config.Elem(key, value); break; case "public-uri": case "root-uri": config.Elem("uri.public", value); break; case "service-dir": config.Elem("storage-dir", value); break; case "collect-interval": int interval; if(!int.TryParse(value, out interval)) { WriteError(key, "invalid collection interval (must be an integer representing seconds)"); return 1; } if(interval > 0) { DebugUtil.SetCollectionInterval(TimeSpan.FromSeconds(interval)); } break; case "auth": config.Elem("authentication-shemes", value); break; default: WriteError(key, "unknown setting"); return 1; } } try { // initialize environment if(config["apikey"].IsEmpty) { string apikey = StringUtil.CreateAlphaNumericKey(32); config.Elem("apikey", apikey); Console.WriteLine("Dream Host APIKEY: {0}", apikey); } Console.WriteLine("-------------------- initializing"); time = DebugUtil.Stopwatch(() => { _host = new DreamHost(config); }); Console.WriteLine("-------------------- initialized {0} secs", time.TotalSeconds); // execute scripts time = DebugUtil.Stopwatch(() => { _host.RunScripts(config, null); }); Console.WriteLine("-------------------- ready {0} secs", time.TotalSeconds); // for UNIX systems, let's also listen to SIGTERM if(SysUtil.IsUnix) { new Thread(SigTermHandler) { IsBackground = true }.Start(); } // check if we can use the console if(useTty) { int debuglevel = 0; // wait for user input then exit while(_host.IsRunning) { Thread.Sleep(250); #region Interactive Key Handler if(Console.KeyAvailable) { ConsoleKeyInfo key = Console.ReadKey(true); switch(key.Key) { case ConsoleKey.Q: case ConsoleKey.Escape: case ConsoleKey.Spacebar: Console.WriteLine("Shutting down"); return 0; case ConsoleKey.G: Console.WriteLine("Full garbage collection pass"); System.GC.Collect(); break; case ConsoleKey.C: Console.Clear(); break; case ConsoleKey.D: switch(++debuglevel) { default: debuglevel = 0; Threading.RendezVousEvent.CaptureTaskState = false; DebugUtil.CaptureStackTrace = false; Console.WriteLine("Debug capture: none"); break; case 1: Threading.RendezVousEvent.CaptureTaskState = true; DebugUtil.CaptureStackTrace = false; Console.WriteLine("Debug capture: task-state only"); break; case 2: Threading.RendezVousEvent.CaptureTaskState = true; DebugUtil.CaptureStackTrace = true; Console.WriteLine("Debug capture: task-state and stack-trace"); break; } break; case ConsoleKey.I: { Console.WriteLine("--- System Information ---"); // show memory Console.WriteLine("Allocated memory: {0}", GC.GetTotalMemory(false)); // show threads int workerThreads; int completionThreads; int dispatcherThreads; int backgroundThreads; AsyncUtil.GetAvailableThreads(out workerThreads, out completionThreads, out dispatcherThreads, out backgroundThreads); int maxWorkerThreads; int maxCompletionThreads; int maxDispatcherThreads; int maxBackgroundThreads; AsyncUtil.GetMaxThreads(out maxWorkerThreads, out maxCompletionThreads, out maxDispatcherThreads, out maxBackgroundThreads); Console.WriteLine("Thread-pool worker threads available: {0} (max: {1})", workerThreads, maxWorkerThreads); Console.WriteLine("Thread-pool completion threads available: {0} (max: {1})", completionThreads, maxCompletionThreads); Console.WriteLine("Dispatcher threads available: {0} (max: {1})", dispatcherThreads, maxDispatcherThreads); Console.WriteLine("Thread-pool background worker threads available: {0} (max: {1})", backgroundThreads, maxBackgroundThreads); // show pending/waiting timers var taskTimerStats = Tasking.TaskTimerFactory.GetStatistics(); Console.WriteLine("Pending timer objects: {0}", taskTimerStats.PendingTimers); Console.WriteLine("Queued timer objects: {0}", taskTimerStats.QueuedTimers); Console.WriteLine("Timer retries: {0}", taskTimerStats.Retries); // show activities var activities = _host.ActivityMessages; Console.WriteLine("Host activities: {0}", activities.Length); foreach(var activity in activities) { Console.WriteLine("* {0}: {1}", activity.Created.ToString(XDoc.RFC_DATETIME_FORMAT), activity.Description); } // show pending tasks Console.WriteLine("Pending rendez-vous events: {0}", Threading.RendezVousEvent.PendingCounter); Console.WriteLine("Pending results: {0}", AResult.PendingCounter); lock(Threading.RendezVousEvent.Pending) { int count = 0; foreach(var entry in Threading.RendezVousEvent.Pending.Values) { ++count; if(entry.Key != null) { var context = entry.Key.GetState<DreamContext>(); if(context != null) { Console.WriteLine("--- DreamContext for pending rendez-vous event #{0} ---", count); Console.WriteLine(context.Uri.ToString(false)); } } Console.WriteLine(); if(entry.Value != null) { Console.WriteLine("--- Stack trace for pending rendez-vous event #{0} ---", count); Console.WriteLine(entry.Value.ToString()); } } } Console.WriteLine("--------------------------"); } break; case ConsoleKey.H: Console.WriteLine("Help:"); Console.WriteLine(" Q - quit application"); Console.WriteLine(" ESC - quit application"); Console.WriteLine(" SPACE - quit application"); Console.WriteLine(" G - full garbage collection"); Console.WriteLine(" C - clear screen"); Console.WriteLine(" D - set debug capture level"); Console.WriteLine(" I - show system information (memory, threads, pending tasks)"); Console.WriteLine(" H - this help text"); break; } } #endregion } } else { _host.WaitUntilShutdown(); } } finally { Console.WriteLine("-------------------- shutting down"); TaskTimerFactory.ShutdownAll(); if(_host != null) { _host.Dispose(); } } return 0; }
public static XDoc ComputeNavigationDocument(IList <NavBE> list, PageBE page, uint splitSibling, uint splitChildren, bool hidden, int max_width) { XDoc result = new XDoc("tree"); List <string> css = new List <string>(); List <string> fetchedChildren = new List <string>(); List <NavBE> childrenNodes = new List <NavBE>(); ulong homepageId = DekiContext.Current.Instance.HomePageId; NavDocStage stage = NavDocStage.None; if (splitSibling > 0) { stage = NavDocStage.SiblingPre; result.Start("siblings-pre"); } else if (splitChildren > 0) { stage = NavDocStage.ChildrenPre; result.Start("siblings-pre").End(); result.Start("children-pre"); } int splitSiblingIndex = 0; int splitChildrenIndex = 0; // fix page_parent_id: it's stored as zero for home and children of home ulong page_parent_id = page.ParentID; if ((page_parent_id == 0) && (page.ID != homepageId)) { page_parent_id = homepageId; } int page_index = 0; // iterate over result set int siblingIndex = 0; int childIndex = 0; foreach (NavBE node in list) { // retrieve page values uint node_id = node.Id; ulong node_parent_id = node.ParentId; bool virtual_node = (node_id >= NEW_PAGE_ID); // fix parent_id: it's stored as zero for home and children of home if ((node_parent_id == 0) && (node_id != homepageId)) { node_parent_id = homepageId; } // set node index (if possible) if (node_id == page.ID) { page_index = siblingIndex; } // check if we need to split the output if (node_id == splitSibling) { splitSiblingIndex = siblingIndex; stage = NavDocStage.ChildrenPre; result.End().Start("children-pre"); if (splitChildren == 0) { stage = NavDocStage.ChildrenPost; result.End().Start("children-post"); } continue; } if (node_id == splitChildren) { splitChildrenIndex = childIndex; stage = NavDocStage.ChildrenPost; result.End().Start("children-post"); continue; } if (((stage == NavDocStage.ChildrenPre) || (stage == NavDocStage.ChildrenPost)) && (splitSibling > 0) && (node_parent_id != splitSibling)) { if (stage == NavDocStage.ChildrenPre) { result.End().Start("children-post"); } stage = NavDocStage.SiblingPost; result.End().Start("siblings-post"); } // check if this node is part of the result set (only include ancestors, siblings, and children of selected node) bool ancestor = false; Title nodeTitle = Title.FromDbPath((NS)node.NameSpace, node.Title, node.DisplayName); if ((node_id != page.ID /* selected */) && (node_parent_id != page_parent_id /* sibling */) && (node_parent_id != page.ID /* child */)) { ancestor = (node_id == page_parent_id /* immediate parent */) || (node_id == homepageId) || nodeTitle.IsParentOf(page.Title); if (!ancestor) { continue; } } // don't include siblings root user pages if (((page.Title.IsUser) || (page.Title.IsSpecial) || (page.Title.IsTemplate)) && (page_parent_id == homepageId) && (node_parent_id == homepageId) && (node_id != page.ID)) { continue; } // 'div' element result.Start("div"); // 'class' attribute css.Clear(); css.Add("node"); if (hidden) { css.Add("closedNode"); } // 'c' (children) attribute fetchedChildren.Clear(); childrenNodes.Clear(); uint parentId = (node_id == homepageId) ? 0 : node_id; for (int i = 0; i < list.Count; ++i) { NavBE child = list[i]; if ((child.ParentId == parentId) & (child.Id != homepageId)) { Title childTitle = Title.FromDbPath((NS)child.NameSpace, child.Title, child.DisplayName); // skip children if they are siblings of the top User: or Template: page if (((page.Title.IsUser) || (page.Title.IsSpecial) || (page.Title.IsTemplate)) && (node_id == homepageId) && !childTitle.IsParentOf(page.Title)) { continue; } childrenNodes.Add(child); fetchedChildren.Add("n" + child.Id); } } int totalChildrenCount = node.ChildCount ?? fetchedChildren.Count; // 'p' (parent) attribute string p = null; if (node_id != homepageId) { p = "n" + node_parent_id; } // 'cd' (child-data) and 'sd' (sibling-data) attribute string cd = null; string sd; if (node_id == page.ID) { // active node if (node_id == homepageId) { css.Add("dockedNode"); css.Add("homeNode"); css.Add("parentClosed"); css.Add("homeSelected"); } else { css.Add("childNode"); if (!hidden) { css.Add("sibling"); } if (totalChildrenCount > 0) { css.Add("parentOpen"); } } css.Add("selected"); // we have all the child data cd = "1"; sd = "1"; } else if (node_parent_id == page_parent_id) { // sibling of active node css.Add("childNode"); if (!hidden) { css.Add("sibling"); } if (totalChildrenCount > 0) { css.Add("parentClosed"); } // if no children exist, then we have all the child data cd = ((totalChildrenCount > 0) ? "0" : "1"); sd = "1"; } else if (node_parent_id == page.ID) { // child of active node css.Add("childNode"); if ((node_parent_id == homepageId) && !hidden) { css.Add("sibling"); } if ((page.ID != homepageId) && !hidden) { css.Add("selectedChild"); } if (totalChildrenCount > 0) { css.Add("parentClosed"); } // if no children exist, then we have all the child data cd = ((totalChildrenCount > 0) ? "0" : "1"); sd = "1"; } else if (ancestor) { // ancestor of active node (parent and above) css.Add("dockedNode"); if (node_id == homepageId) { css.Add("homeNode"); } if (node_id == page_parent_id) { css.Add("lastDocked"); } css.Add("parentClosed"); // check if we are the last docked node or have more than one child if ((node_id == page_parent_id) || (totalChildrenCount == 1)) { cd = "1"; } else { // find the child node that is actually included in the tree foreach (NavBE child in childrenNodes) { Title childTitle = Title.FromDbPath((NS)child.NameSpace, child.Title, child.DisplayName); if (childTitle.IsParentOf(page.Title)) { cd = "n" + child.Id; break; } } if (cd == null) { #if DEBUG throw new Exception("unexpected [expected to find child nodes]"); #else cd = "1"; #endif } } // check if parent of this node has more than one child if ((node_id == homepageId) || (result[string.Format("div[@id='{0}']/@cd", "n" + node_parent_id)].Contents == "1")) { sd = "1"; } else { sd = "0"; } } else { throw new Exception("unexpected"); } // attributes result.Attr("class", string.Join(" ", css.ToArray())); result.Attr("id", "n" + node_id.ToString()); if (fetchedChildren.Count > 0) { result.Attr("c", string.Join(",", fetchedChildren.ToArray())); } if (p != null) { result.Attr("p", p); } // NOTE (steveb): this is used by the JS in the browser to correlate nodes in the pane (it's never used by anything else; hence the different format) string safe_path = nodeTitle.AsPrefixedDbPath().Replace("//", "%2f"); result.Attr("path", (safe_path.Length == 0) ? string.Empty : (safe_path + "/")); // root page always has all children if they belong to User:, Template:, or Special: namespace if ((cd != "1") && !virtual_node && ((page.Title.IsMain) || (((page.Title.IsTemplate) || (page.Title.IsUser) || (page.Title.IsSpecial)) && (node_id != homepageId)))) { result.Attr("cd", cd); } // children of root page always have all siblings if they belong to User:, Template:, or Special: namespace if ((sd != "1") && !virtual_node && ((page.Title.IsMain) || (((page.Title.IsTemplate) || (page.Title.IsUser) || (page.Title.IsSpecial)) && (node_parent_id != homepageId)))) { result.Attr("sd", "0"); } if (virtual_node || ((node_id == homepageId) && (!page.Title.IsMain))) { result.Attr("reload", "1"); } // div contents result.Start("a"); // set page title string name = nodeTitle.AsUserFriendlyName(); result.Attr("href", Utils.AsPublicUiUri(nodeTitle)); result.Attr("title", name); result.Elem("span", DekiWikiService.ScreenFont.Truncate(name, max_width)); result.End(); result.End(); if (node_parent_id == page_parent_id) { ++siblingIndex; } else if (node_parent_id == page.ID) { ++childIndex; } } // post-process created list if ((splitSibling > 0) || (splitChildren > 0)) { if (stage == NavDocStage.SiblingPre) { result.End().Start("siblings-post"); result.End().Start("children-pre"); result.End().Start("children-post"); } else if (stage == NavDocStage.ChildrenPre) { result.End().Start("children-post"); result.End().Start("siblings-post"); } else if (stage == NavDocStage.ChildrenPost) { result.End().Start("siblings-post"); } result.End(); // truncate siblings and children TruncateList(result["siblings-pre/div | siblings-post/div"], ~splitSiblingIndex, hidden); TruncateList(result["children-pre/div | children-post/div"], ~splitChildrenIndex, hidden); } else if (hidden) { // truncate full list TruncateList(result["div"], 0, hidden); } else { // truncate children of selected node TruncateList(result[string.Format("div[@p='n{0}']", page.ID)], 0, hidden); // truncate siblings of selected node TruncateList(result[string.Format("div[@p='n{0}']", page_parent_id)], page_index, hidden); } return(result); }
//--- Class Methods --- public static void AppendXml(this RecentChangeEntry change, XDoc doc) { doc.Start("change"); doc.Elem("rc_id", change.Id); if (change.ExtraComments != null) { foreach (var comment in change.ExtraComments) { doc.Start("rc_comment") .Attr("author", comment.Item1) .Attr("fullname", comment.Item2) .Value(comment.Item3) .End(); } } else { doc.Elem("rc_comment", change.Comment); } doc.Elem("rc_cur_id", change.CurId); doc.Elem("rc_last_oldid", change.LastOldId); doc.Elem("rc_this_oldid", change.ThisOldId); doc.Elem("rc_namespace", (int)change.Namespace); doc.Elem("rc_timestamp", DbUtils.ToString(change.Timestamp)); doc.Elem("rc_title", change.Title); doc.Elem("rc_type", (int)change.Type); doc.Elem("rc_moved_to_ns", (int)change.MovedToNs); doc.Elem("rc_moved_to_title", change.MovedToTitle); if ((change.SortedAuthors != null) && (change.SortedAuthors.Count > 1)) { foreach (var author in change.SortedAuthors) { doc.Elem("rc_user_name", author.Key); doc.Elem("rc_full_name", author.Value); } } else { doc.Elem("rc_user_name", change.Username); doc.Elem("rc_full_name", change.Fullname); } doc.Elem("rc_page_exists", change.PageExists ? 1 : 0); doc.Elem("rc_revision", change.Revision); doc.Elem("cmnt_id", change.CmntId); doc.Elem("cmnt_number", change.CmntNumber); doc.Elem("cmnt_content", change.CmntContent); doc.Elem("cmnt_content_mimetype", change.CmntMimetype); doc.Elem("cmnt_deleted", change.CmntDeleted ? 1 : 0); doc.Elem("old_is_hidden", change.OldIsHidden); doc.Elem("edit_count", change.EditCount); doc.Elem("rc_prev_revision", change.PreviousRevision); doc.Elem("rc_summary", change.Summary); doc.End(); }
public Yield GetNavigationChildrenSiblings(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.QueryNavSiblingsAndChildrenData(page, context.Culture); if (ShowDebug(context)) { response.Return(DreamMessage.Ok(NavBL.ConvertNavPageListToDoc(list))); } else { XDoc doc = NavBL.ComputeNavigationDocument(list, page, (uint)page.ID, exclude, 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(); // add name of children nodes result.Start("children"); nodes = new System.Text.StringBuilder(); 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.Elem("pre", doc["children-pre"].Contents); result.Elem("post", doc["children-post"].Contents); } else { result.Value(doc["children-post"].Contents); } result.End(); result.End(); response.Return(DreamMessage.Ok(result)); } } yield break; }
//--- 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(); }
//--- Class Methods --- public static ServiceBE StartService(ServiceBE service, bool forceRefresh, bool disableOnFailure) { // create subordinate request id for service start var dreamContext = DreamContext.Current; var requestId = dreamContext.GetState <string>(DreamHeaders.DREAM_REQUEST_ID); dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId + "-service_" + service.Id); try { var stopwatch = Stopwatch.StartNew(); service.ServiceLastStatus = string.Empty; StopService(service.Id, service, ServiceStopType.Restart); DekiContext context = DekiContext.Current; bool dirtyServiceEntity = false; XUri location; ServiceRepository.IServiceInfo serviceInfo = null; try { // check if service is local if (service.ServiceLocal) { if (string.IsNullOrEmpty(service.SID)) { throw new Exception("missing SID"); } // start service if (IsLocalAuthService(service)) { // this service is the built-in authentication provider; no need to start it location = context.Deki.Self; } else { // convert local service configuration into an xdoc XDoc config = new XDoc("config"); foreach (KeyValuePair <string, string> configEntry in ArrayUtil.AllKeyValues(service.Config)) { config.InsertValueAt(configEntry.Key, configEntry.Value); } // if no apikey was provided, create a random one so that CreateService doesn't inject the parent one if (config["apikey"].IsEmpty) { config.Elem("apikey", StringUtil.CreateAlphaNumericKey(16)); } // add information for service to callback into deki if (config["uri.deki"].IsEmpty) { config.Elem("uri.deki", context.Deki.Self); config.Elem("wikiid.deki", context.Instance.Id); // Providing master apikey to service for setups that don't use per instance keys config.Elem("apikey.deki", context.Instance.ApiKey.IfNullOrEmpty(context.Deki.MasterApiKey)); } // the service location must use the service ID and the instance ID string servicePath = string.Format("services/{0}/{1}", context.Instance.Id, service.Id); _log.DebugFormat("starting service '{0}' at path {1} w/ namespace {2}", service.SID, servicePath, service.Preferences["namespace"]); serviceInfo = context.Instance.CreateLocalService(service, servicePath, config); location = serviceInfo.ServiceUri; } // check if the service uri has changed since last invocation (happens when service is started for the first time or server GUID has changed) if (!service.Uri.EqualsInvariantIgnoreCase(location.ToString())) { dirtyServiceEntity = true; service.Uri = location.ToString(); } } else { _log.DebugFormat("registering remote service '{0}'", service.SID); if (string.IsNullOrEmpty(service.Uri)) { throw new Exception("missing URI"); } location = new XUri(service.Uri); serviceInfo = context.Instance.RegisterRemoteService(service, location); } // check if service is an Extension service if (service.Type == ServiceType.EXT) { if (service.ServiceLocal) { _log.DebugFormat("registering service '{0}' as extension", service.SID); } ExtensionBL.StartExtensionService(context, service, serviceInfo, forceRefresh); } //Successfully starting a service enables it. if (!service.ServiceEnabled) { dirtyServiceEntity = true; service.ServiceEnabled = true; } } catch (Exception e) { dirtyServiceEntity = true; DreamMessage dm = null; if (e is DreamResponseException) { dm = ((DreamResponseException)e).Response; string message = dm.HasDocument ? dm.ToDocument()[".//message"].AsText.IfNullOrEmpty(e.Message) : dm.ToText(); service.ServiceLastStatus = string.Format("unable to initialize service ({0})", message); } else { service.ServiceLastStatus = e.GetCoroutineStackTrace(); } if (serviceInfo != null) { try { context.Instance.DeregisterService(service.Id); } catch { } } // A service that fails to start becomes disabled if it's started explicitly (not during deki startup) if (disableOnFailure) { service.ServiceEnabled = false; } _log.ErrorExceptionMethodCall(e, "StartService", string.Format("Unable to start local service id '{0}' with SID '{1}' Error: '{2}'", service.Id, service.SID, service.ServiceLastStatus)); if (dm != null) { throw new ExternalServiceResponseException(dm); } else { throw; } } finally { // don't update remote services that haven't changed if (dirtyServiceEntity) { service = UpdateService(service); } } stopwatch.Stop(); _log.InfoFormat("Service '{0}' ({1}) started in {2}ms", service.Description, service.SID, stopwatch.ElapsedMilliseconds); return(service); } finally { // restore the request id dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId); } }
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; }
public static XDoc Heading(this XDoc doc, int level, string value) { return(doc.Elem("H" + (level + 1), value)); }
private XDoc BuildBugListHTMLTable(RemoteIssue[] issues) { XDoc ret = new XDoc("div").Attr("class", "DW-table Jira-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", "Priority") .Elem("th", "Opened By") .Elem("th", "Assigned To") .End(); int count = 0; foreach (RemoteIssue bug in issues) { count++; RemoteStatus status = null; if (!string.IsNullOrEmpty(bug.status)) { _statuses.TryGetValue(bug.status, out status); } RemotePriority priority = null; if (!string.IsNullOrEmpty(bug.priority)) { _priorities.TryGetValue(bug.priority, out priority); } string trClass = string.Format("{0} {1}", (count % 2 == 0) ? "even" : "odd", status == null ? string.Empty : status.name); ret.Start("tr").Attr("class", trClass); ret.Start("td"); ret = BuildBugLink(bug, ret); ret.End(); //td; ret.Elem("td", bug.summary); if (status == null) { ret.Elem("td", ""); } else { ret.Start("td").Start("img").Attr("src", status.icon).Attr("alt", status.name).Attr("title", status.description).End().Value(status.name).End(); } if (priority == null) { ret.Elem("td"); } else { ret.Start("td").Start("img").Attr("src", priority.icon).Attr("alt", priority.name).Attr("title", priority.description).End().Value(priority.name).End(); } ret.Elem("td", bug.reporter ?? string.Empty); ret.Elem("td", bug.assignee ?? string.Empty); ret.End(); //tr } ret.End(); // table return(ret); }
//--- 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 Yield ValidateOpenIdResponse(DreamContext context, DreamMessage request, Result<DreamMessage> response) { XUri publicUri = new XUri(context.GetParam("url", null)); NameValueCollection queryColl = System.Web.HttpUtility.ParseQueryString(context.GetParam("query", null)); // process the response, including validating the endpoint of the claimed identifier. OpenIdRelyingParty openid = new OpenIdRelyingParty(null, publicUri, queryColl); var openIdResponse = openid.Response; if (openIdResponse != null) { switch (openIdResponse.Status) { case AuthenticationStatus.Authenticated: // Throw an exception if there is a regex for acceptable // identifiers defined, and the ID does not match. if (!String.IsNullOrEmpty(_validIdPattern)) { Regex identifierAccept = new Regex(_validIdPattern); if (!identifierAccept.IsMatch(openIdResponse.ClaimedIdentifier)) { _log.InfoFormat("Identifier {0} denied access by valid-id-pattern regular expression {1}", openIdResponse.ClaimedIdentifier, _validIdPattern); throw new DreamBadRequestException("This service is configured to deny access to this OpenID identifier."); } } var claimsResponse = openIdResponse.GetExtension<ClaimsResponse>(); var fetchResponse = openIdResponse.GetExtension<FetchResponse>(); XDoc result = new XDoc("openid"); result.Attr("validated", true); result.Elem("identifier", openIdResponse.ClaimedIdentifier); // SREG response if (claimsResponse != null) { string email = claimsResponse.Email; if (email != null) { result.Elem("email", email); _log.DebugFormat("E-mail address from SREG: {0}", email); } } // AX response if (fetchResponse != null) { foreach (AttributeValues v in fetchResponse.Attributes) { if (v.TypeUri == WellKnownAttributes.Contact.Email) { IList<string> emailAddresses = v.Values; string email = emailAddresses.Count > 0 ? emailAddresses[0] : null; result.Elem("email", email); _log.DebugFormat("E-mail address from AX: {0}", email); } } } response.Return(DreamMessage.Ok(result)); break; case AuthenticationStatus.Canceled: _log.InfoFormat("Authentication was cancelled by the user."); throw new DreamBadRequestException("Authentication was cancelled by the user."); case AuthenticationStatus.Failed: _log.InfoFormat("Authentication failed: " + openIdResponse.Exception.Message); throw new DreamBadRequestException("Authentication failed: " + openIdResponse.Exception.Message); default: _log.WarnFormat("Authentication error: " + openIdResponse.Exception.Message); throw new DreamBadRequestException("Authentication error: " + openIdResponse.Exception.Message); } } else { _log.Warn("OpenID response was null"); throw new DreamBadRequestException("No OpenID response was returned."); } 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."); } } }
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; }
//--- 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; }
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; }
public Yield ValidateOpenIdResponse(DreamContext context, DreamMessage request, Result <DreamMessage> response) { XUri publicUri = new XUri(context.GetParam("url", null)); NameValueCollection queryColl = System.Web.HttpUtility.ParseQueryString(context.GetParam("query", null)); // process the response, including validating the endpoint of the claimed identifier. OpenIdRelyingParty openid = new OpenIdRelyingParty(null, publicUri, queryColl); var openIdResponse = openid.Response; if (openIdResponse != null) { switch (openIdResponse.Status) { case AuthenticationStatus.Authenticated: // Throw an exception if there is a regex for acceptable // identifiers defined, and the ID does not match. if (!String.IsNullOrEmpty(_validIdPattern)) { Regex identifierAccept = new Regex(_validIdPattern); if (!identifierAccept.IsMatch(openIdResponse.ClaimedIdentifier)) { _log.InfoFormat("Identifier {0} denied access by valid-id-pattern regular expression {1}", openIdResponse.ClaimedIdentifier, _validIdPattern); throw new DreamBadRequestException("This service is configured to deny access to this OpenID identifier."); } } var claimsResponse = openIdResponse.GetExtension <ClaimsResponse>(); var fetchResponse = openIdResponse.GetExtension <FetchResponse>(); XDoc result = new XDoc("openid"); result.Attr("validated", true); result.Elem("identifier", openIdResponse.ClaimedIdentifier); // SREG response if (claimsResponse != null) { string email = claimsResponse.Email; if (email != null) { result.Elem("email", email); _log.DebugFormat("E-mail address from SREG: {0}", email); } } // AX response if (fetchResponse != null) { foreach (AttributeValues v in fetchResponse.Attributes) { if (v.TypeUri == WellKnownAttributes.Contact.Email) { IList <string> emailAddresses = v.Values; string email = emailAddresses.Count > 0 ? emailAddresses[0] : null; result.Elem("email", email); _log.DebugFormat("E-mail address from AX: {0}", email); } } } response.Return(DreamMessage.Ok(result)); break; case AuthenticationStatus.Canceled: _log.InfoFormat("Authentication was cancelled by the user."); throw new DreamBadRequestException("Authentication was cancelled by the user."); case AuthenticationStatus.Failed: _log.InfoFormat("Authentication failed: " + openIdResponse.Exception.Message); throw new DreamBadRequestException("Authentication failed: " + openIdResponse.Exception.Message); default: _log.WarnFormat("Authentication error: " + openIdResponse.Exception.Message); throw new DreamBadRequestException("Authentication error: " + openIdResponse.Exception.Message); } } else { _log.Warn("OpenID response was null"); throw new DreamBadRequestException("No OpenID response was returned."); } yield break; }
private void ConvertUsers(string htpasswdFilePath) { WriteLineToConsole("Converting users..."); string[] userLines = File.ReadAllLines(htpasswdFilePath); Dictionary<string, string> dekiUsers = new Dictionary<string, string>(); DreamMessage usersResponse = _dekiPlug.At("users").With("limit", int.MaxValue).GetAsync().Wait(); if (usersResponse.Status != DreamStatus.Ok) { WriteErrorResponse(usersResponse, "Error while reciving users from Deki. Users not converted."); return; } XDoc dekiUsersDoc = usersResponse.AsDocument(); foreach (XDoc userDoc in dekiUsersDoc["//user"]) { string dekiUserName = userDoc["nick"].AsText; dekiUsers[dekiUserName.ToLower()] = null; } foreach (string userLine in userLines) { string user = userLine.Trim(); if (string.IsNullOrEmpty(user)) { continue; } int colonIndex = user.IndexOf(':'); if (colonIndex <= 0) { continue; } string userName = user.Substring(0, colonIndex); if (_convertedUsers.ContainsKey(userName)) { continue; } string eMail = null; int lastColonIndex = user.LastIndexOf(':'); if ((lastColonIndex > 0) && (lastColonIndex > colonIndex) && (lastColonIndex + 1 < user.Length)) { eMail = user.Substring(lastColonIndex + 1, user.Length - lastColonIndex - 1); } string newUserName = userName; int userNum = 0; while (dekiUsers.ContainsKey(newUserName.ToLower())) { userNum++; newUserName = userName + userNum.ToString(); } if (newUserName != userName) { WriteLineToConsole("TWiki user \"" + userName + "\" converted as \"" + newUserName + "\" becouse of existing same user in Deki"); } XDoc usersDoc = new XDoc("user") .Elem("username", newUserName); if (!string.IsNullOrEmpty(eMail)) { usersDoc.Elem("email", eMail); } string newPassword = Guid.NewGuid().ToString(); DreamMessage res = _dekiPlug.At("users").With("accountpassword", newPassword).PostAsync(usersDoc).Wait(); WriteErrorResponse(res, "Error converting user \"" + userName + "\""); XDoc resDoc = res.AsDocument(); int dekiId = resDoc["@id"].AsInt.Value; _convertedUsers[userName] = new TWikiUser(userName, newUserName, dekiId); } WriteLineToConsole("Users converted!!!"); WriteLineToConsole(); }
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; }
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; }
//--- 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 CreateStorageService() { // create storage service XDoc config = new XDoc("config"); config.Elem("path", "storage"); config.Elem("sid", "sid://mindtouch.com/2007/03/dream/storage"); config.Elem("folder", _storageFolder); //DreamMessage result = _host.Self.At("services").PostAsync(config).Wait(); DreamMessage result = _hostInfo.LocalHost.At("host", "services").With("apikey", _hostInfo.ApiKey).PostAsync(config).Wait(); Assert.IsTrue(result.IsSuccessful, result.ToText()); // initialize storage plug _storage = _hostInfo.LocalHost.At("storage"); }
private static XDoc GetDefaultErrorResponse(DreamStatus status, string title, string message) { XDoc result = new XDoc("error"); DreamContext context = DreamContext.CurrentOrNull; if((context != null) && (context.Env.Self != null)) { result.WithXslTransform(context.AsPublicUri(context.Env.Self).At("resources", "error.xslt").Path); } result.Elem("status", (int)status).Elem("title", title).Elem("message", message); if(context != null) { result.Elem("uri", context.Uri); } return result; }
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 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; }
public Yield GetFileOrFolderListing(DreamContext context, DreamMessage request, Result <DreamMessage> response) { bool head = StringUtil.EqualsInvariant(context.Verb, "HEAD"); string path = GetPath(context); DreamMessage result; if (File.Exists(path)) { // dealing with a file request TouchMeta(path); // check if request contains a 'if-modified-since' header var lastmodified = File.GetLastWriteTime(path); if (request.CheckCacheRevalidation(lastmodified) && (lastmodified.Year >= 1900)) { response.Return(DreamMessage.NotModified()); yield break; } // retrieve file try { result = DreamMessage.FromFile(path, head); } catch (FileNotFoundException) { result = DreamMessage.NotFound("file not found"); } catch (Exception) { result = DreamMessage.BadRequest("invalid path"); } // add caching headers if file was found if (!head && result.IsSuccessful) { // add caching information; this will avoid unnecessary data transfers by user-agents with caches result.SetCacheMustRevalidate(lastmodified); } } else if (Directory.Exists(path)) { // dealing with a directory request if (head) { // HEAD for a directory doesn't really mean anything, so we just return ok, to indicate that it exists result = DreamMessage.Ok(); } else { var doc = new XDoc("files"); // list directory contents var directories = Directory.GetDirectories(path); foreach (var dir in directories) { if (dir.EndsWithInvariantIgnoreCase(META)) { continue; } doc.Start("folder") .Elem("name", Path.GetFileName(dir)) .End(); } foreach (var filepath in Directory.GetFiles(path)) { var file = new FileInfo(filepath); doc.Start("file") .Elem("name", file.Name) .Elem("size", file.Length) .Elem("date.created", file.CreationTimeUtc) .Elem("date.modified", file.LastWriteTimeUtc); var entry = SyncMeta(filepath); if (entry != null) { doc.Elem("date.expire", entry.When); doc.Elem("date.ttl", entry.TTL); } doc.End(); } result = DreamMessage.Ok(doc); } } else { // nothin here result = DreamMessage.NotFound("no such file or folder"); } response.Return(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); }
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(); }
private void MoveGroups() { DreamMessage msg = _dekiPlug.At("groups").With("limit", int.MaxValue).GetAsync().Wait(); if (msg.Status != DreamStatus.Ok) { WriteLineToConsole("Error while receiving groups from Deki. Groups not converted."); WriteErrorResponse(msg); return; } Dictionary <string, string> dekiGroups = new Dictionary <string, string>(); XDoc groupsDoc = msg.AsDocument(); foreach (XDoc groupDoc in groupsDoc["//group"]) { string dekiGroupName = groupDoc["groupname"].AsText; dekiGroups[dekiGroupName.ToLower()] = null; } string[] confluenceGroupNames = _confluenceService.GetGroups(); foreach (string confluenceGroupName in confluenceGroupNames) { string dekiGroupName; if (!_convertedGroups.ContainsKey(confluenceGroupName.ToLower())) { int groupNum = 0; dekiGroupName = confluenceGroupName; while (dekiGroups.ContainsKey(dekiGroupName.ToLower())) { groupNum++; dekiGroupName = confluenceGroupName + groupNum.ToString(); } if (dekiGroupName != confluenceGroupName) { WriteLineToConsole("Confluence group \"" + confluenceGroupName + "\" converted as \"" + dekiGroupName + "\" becouse of existing same group in Deki"); } XDoc newGroupDoc = new XDoc("group"); newGroupDoc.Elem("name", dekiGroupName) .Start("users"); foreach (ACConverterUserInfo convertedUser in _convertedUsers.Values) { if (Array.IndexOf(convertedUser.ConfluenceUserGroupNames, confluenceGroupName) >= 0) { newGroupDoc.Start("user").Attr("id", convertedUser.DekiUserId).End(); } } newGroupDoc.End(); Log.DebugFormat("Creating group: {0}", dekiGroupName); DreamMessage res = _dekiPlug.At("groups").PostAsync(newGroupDoc).Wait(); if (res.Status != DreamStatus.Ok) { WriteLineToLog("Error converting group \"" + confluenceGroupName + "\""); WriteErrorResponse(res); WriteErrorRequest(newGroupDoc); continue; } XDoc resGroupsDoc = res.AsDocument(); int newDekiGroupId = resGroupsDoc["@id"].AsInt.Value; ACConverterGroupInfo convertedGroup = new ACConverterGroupInfo(confluenceGroupName, dekiGroupName, newDekiGroupId); _convertedGroups[confluenceGroupName.ToLower()] = convertedGroup; } else { //This group already converted during previous ACConverter start dekiGroupName = _convertedGroups[confluenceGroupName.ToLower()].DekiGroupName; XDoc usersDoc = new XDoc("users"); foreach (ACConverterUserInfo convertedUser in _convertedUsers.Values) { if (Array.IndexOf(convertedUser.ConfluenceUserGroupNames, confluenceGroupName) >= 0) { usersDoc.Start("user").Attr("id", convertedUser.DekiUserId).End(); } } DreamMessage res = _dekiPlug.At("groups", _convertedGroups[confluenceGroupName.ToLower()].DekiGroupId.ToString(), "users").PutAsync(usersDoc).Wait(); if (res.Status != DreamStatus.Ok) { WriteLineToLog("Error converting group's users"); WriteErrorResponse(res); WriteErrorRequest(usersDoc); } } } }