public Yield GetFileRevisions(DreamContext context, DreamMessage request, Result <DreamMessage> response) { CheckResponseCache(context, false); //Default change filter is CONTENT changes to preserve backwards compat string changeFilterStr = context.GetParam("changefilter", AttachmentBL.DEFAULT_REVISION_FILTER.ToString()); ResourceBE.ChangeOperations changeFilter = ResourceBE.ChangeOperations.UNDEFINED; if (!string.IsNullOrEmpty(changeFilterStr)) { if (StringUtil.EqualsInvariantIgnoreCase("all", changeFilterStr)) { changeFilter = ResourceBE.ChangeOperations.UNDEFINED; } else if (!SysUtil.TryParseEnum(changeFilterStr, out changeFilter)) { throw new DreamBadRequestException("changefilter value is invalid. Possible values are ALL, " + string.Join(",", Enum.GetNames(typeof(ResourceBE.ChangeOperations)))); } } PageBE parentPage = null; ResourceBE fileRevision = GetAttachment(context, request, Permissions.READ, false, false, out parentPage); XUri listUri = AttachmentBL.Instance.GetUri(fileRevision).At("revisions").With("changefilter", changeFilterStr.ToLowerInvariant()); XDoc ret = AttachmentBL.Instance.GetFileRevisionsXml(fileRevision, changeFilter, listUri, fileRevision.Revision); response.Return(DreamMessage.Ok(ret)); yield break; }
public Yield GetTags(DreamContext context, DreamMessage request, Result <DreamMessage> response) { string type = DreamContext.Current.GetParam("type", ""); string fromStr = DreamContext.Current.GetParam("from", ""); string toStr = DreamContext.Current.GetParam("to", ""); bool showPages = DreamContext.Current.GetParam("pages", false); string partialName = DreamContext.Current.GetParam("q", ""); // parse type TagType tagType = TagType.ALL; if (!string.IsNullOrEmpty(type) && !SysUtil.TryParseEnum(type, out tagType)) { throw new DreamBadRequestException("Invalid type parameter"); } // check and validate from date DateTime from = (tagType == TagType.DATE) ? DateTime.Now : DateTime.MinValue; if (!string.IsNullOrEmpty(fromStr) && !DateTime.TryParse(fromStr, out from)) { throw new DreamBadRequestException("Invalid from date parameter"); } // check and validate to date DateTime to = (tagType == TagType.DATE) ? from.AddDays(30) : DateTime.MaxValue; if (!string.IsNullOrEmpty(toStr) && !DateTime.TryParse(toStr, out to)) { throw new DreamBadRequestException("Invalid to date parameter"); } // execute query var tagBL = new TagBL(); var tags = tagBL.GetTags(partialName, tagType, from, to); XDoc doc = tagBL.GetTagListXml(tags, "tags", null, showPages); response.Return(DreamMessage.Ok(doc)); 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 GetFile(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PageBE parentPage = null; DreamMessage responseMsg = null; ResourceBE fileRevision = GetAttachment(context, request, Permissions.READ, true, false, out parentPage); if (fileRevision.IsHidden) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); } // check if only file information is requested if (context.Verb == Verb.HEAD) { response.Return(new DreamMessage(DreamStatus.Ok, null, fileRevision.MimeType, (long)fileRevision.Size, Stream.Null)); yield break; } try { if (request.CheckCacheRevalidation(fileRevision.Timestamp)) { responseMsg = DreamMessage.NotModified(); } if (responseMsg == null) { #region Preview related parameter parsing string sFormat = context.GetParam("format", string.Empty); string sRatio = context.GetParam("ratio", string.Empty); uint height = context.GetParam <uint>("height", 0); uint width = context.GetParam <uint>("width", 0); string cachedSize = context.GetParam("size", string.Empty); // check 'ratio' parameter RatioType ratio = RatioType.UNDEFINED; if (!string.IsNullOrEmpty(sRatio)) { switch (sRatio.ToLowerInvariant().Trim()) { case "var": case "variable": ratio = RatioType.VARIABLE; break; case "fixed": ratio = RatioType.FIXED; break; default: throw new AttachmentFileRatioInvalidArgumentException(); } } // check 'size' parameter SizeType size = SizeType.UNDEFINED; if (!string.IsNullOrEmpty(cachedSize) && !SysUtil.TryParseEnum(cachedSize.Trim(), out size)) { throw new AttachmentFilesizeInvalidArgumentException(); } // check 'format' parameter FormatType format = FormatType.UNDEFINED; if (!string.IsNullOrEmpty(sFormat) && !SysUtil.TryParseEnum(sFormat.Trim(), out format)) { throw new AttachmentFileFormatInvalidArgumentException(); } #endregion //if any preview related parameters are set, do preview logic. Otherwise return the file StreamInfo file = null; if ((size != SizeType.UNDEFINED && size != SizeType.ORIGINAL) || ratio != RatioType.UNDEFINED || format != FormatType.UNDEFINED || height != 0 || width != 0 ) { file = AttachmentPreviewBL.RetrievePreview(fileRevision, height, width, ratio, size, format); } else { var isMSWebDAV = MSWEBDAV_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty); file = DekiContext.Current.Instance.Storage.GetFile(fileRevision, SizeType.ORIGINAL, !isMSWebDAV); } // prepare response if (file == null) { throw new AttachmentDoesNotExistFatalException(fileRevision.ResourceId, fileRevision.Revision); } if (file.Uri != null) { responseMsg = DreamMessage.Redirect(file.Uri); } else { bool inline = fileRevision.MetaXml.ImageHeight.HasValue; // see if we can use the MimeType map for allowing inlining if (!inline) { // if IE inline security is not disabled bool isIE = false; if (!DekiContext.Current.Instance.EnableUnsafeIEContentInlining) { // check the user agent to see if we're dealing with IE isIE = MSIE_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty); } // see if the mime-type could allow inlining inline = DekiContext.Current.Instance.MimeTypeCanBeInlined(fileRevision.MimeType); if (inline && isIE) { // check whether the creator of the file had unsafecontent permission, to override IE security IList <ResourceBE> revisions = ResourceBL.Instance.GetResourceRevisions(fileRevision.ResourceId, ResourceBE.ChangeOperations.CONTENT, SortDirection.DESC, 1); UserBE lastContentEditor = UserBL.GetUserById(revisions[0].UserId); inline = PermissionsBL.IsUserAllowed(lastContentEditor, parentPage, Permissions.UNSAFECONTENT); } } responseMsg = DreamMessage.Ok(fileRevision.MimeType, file.Length, file.Stream); responseMsg.Headers["X-Content-Type-Options"] = "nosniff"; responseMsg.Headers.ContentDisposition = new ContentDisposition(inline, fileRevision.Timestamp, null, null, fileRevision.Name, file.Length, request.Headers.UserAgent); // MSIE6 will delete a downloaded file before the helper app trying to use it can get to it so we //have to do custom cache control headers for MSIE6 so that the file can actually be opened if (MSIE6_USER_AGENT_REGEX.IsMatch(request.Headers.UserAgent ?? string.Empty)) { responseMsg.Headers["Expires"] = "0"; responseMsg.Headers.Pragma = "cache"; responseMsg.Headers.CacheControl = "private"; } else { responseMsg.SetCacheMustRevalidate(fileRevision.Timestamp); } } } } catch { if (responseMsg != null) { responseMsg.Close(); } throw; } response.Return(responseMsg); yield break; }
private DekiScriptInvocationTargetDescriptor ConvertFunction(XDoc function) { string functionName = function["name"].AsText; if (string.IsNullOrEmpty(functionName)) { _log.WarnFormat("function without name in script {0}; skipping function definition", _manifestUri); return(null); } // determine function access level DreamAccess access; switch (function["access"].AsText ?? "public") { case "private": access = DreamAccess.Private; break; case "internal": access = DreamAccess.Internal; break; case "public": access = DreamAccess.Public; break; default: _log.WarnFormat("unrecognized access level '{0}' for function {1} in script {2}; defaulting to public", function["access"].AsText, functionName, _manifestUri); access = DreamAccess.Public; break; } // convert parameters List <DekiScriptParameter> parameters = new List <DekiScriptParameter>(); foreach (XDoc param in function["param"]) { string paramName = param["@name"].AsText; // determine if parameter has a default value string paramDefault = param["@default"].AsText; DekiScriptLiteral paramDefaultExpression = DekiScriptNil.Value; bool paramOptional = false; if (paramDefault != null) { paramOptional = true; try { paramDefaultExpression = ScriptRuntime.Evaluate(DekiScriptParser.Parse(Location.Start, paramDefault), DekiScriptEvalMode.Evaluate, ScriptRuntime.CreateEnv()); } catch (Exception e) { _log.ErrorExceptionFormat(e, "invalid default value for parameter {0} in function {1} in script {2}; skipping function definition", paramName, functionName, _manifestUri); return(null); } } else { paramOptional = (param["@optional"].AsText == "true"); } // determine parameter type string paramType = param["@type"].AsText ?? "any"; DekiScriptType paramScriptType; if (!SysUtil.TryParseEnum(paramType, out paramScriptType)) { _log.WarnFormat("unrecognized param type '{0}' for parameter {1} in function {2} in script {3}; defaulting to any", paramType, paramName, functionName, _manifestUri); paramScriptType = DekiScriptType.ANY; } // add parameter parameters.Add(new DekiScriptParameter(paramName, paramScriptType, paramOptional, param.Contents, typeof(object), paramDefaultExpression)); } var parameterArray = parameters.ToArray(); // determine function body XDoc ret = function["return"]; string src = ret["@src"].AsText; string type = ret["@type"].AsText; DekiScriptExpression expression; if (!string.IsNullOrEmpty(src)) { // 'src' attribute is set, load the script from it XDoc script; if (_manifestUri != null) { // check if uri is relative XUri scriptUri = XUri.TryParse(src) ?? _manifestUri.AtPath(src); script = Plug.New(scriptUri).Get().ToDocument(); } else { // check if filename is relative if (!Path.IsPathRooted(src)) { src = Path.Combine(_resourcesPath, src); } script = XDocFactory.LoadFrom(src, MimeType.XML); } expression = DekiScriptParser.Parse(script); type = type ?? "xml"; } else if (!ret["html"].IsEmpty) { // <return> element contains a <html> node; parse it as a script expression = DekiScriptParser.Parse(ret["html"]); type = type ?? "xml"; } else if (!ret.IsEmpty) { // <return> element contains something else; use the text contents as deki-script expression var location = new Location(string.Format("/function[name={0}]/return", functionName)); expression = DekiScriptParser.Parse(location, function["return"].AsText ?? string.Empty); expression = DekiScriptExpression.ReturnScope(location, expression); type = type ?? "any"; } else { _log.WarnFormat("function {0} has no body in script {1}; skipping function definition", functionName, _manifestUri); return(null); } // determine return type DekiScriptType returnScriptType; if (!SysUtil.TryParseEnum(type, out returnScriptType)) { _log.WarnFormat("unrecognized return type '{0}' for function {1} in script {2}; defaulting to any", type, functionName, _manifestUri); returnScriptType = DekiScriptType.ANY; } // create function descriptor var target = new DekiScriptScriptFunctionInvocationTarget(access, parameterArray, expression, _commonEnv, returnScriptType); string description = function["description"].AsText; string transform = function["@transform"].AsText; return(new DekiScriptInvocationTargetDescriptor(access, false, false, functionName, parameterArray, returnScriptType, description, transform, target)); }