public void BE_hashes_stream() { var value = StringUtil.CreateAlphaNumericKey(20); var be = new ResourceContentBE(value, MimeType.TEXT_UTF8); Assert.AreEqual(StringUtil.ComputeHashString(value, Encoding.UTF8), be.ComputeHashString()); }
public void Can_roundtrip_text_through_BE() { var text = StringUtil.CreateAlphaNumericKey(20); var be = new ResourceContentBE(text, MimeType.TEXT_UTF8); Assert.AreEqual(text, be.ToText()); }
private static ResourceBE PopulateFile(IDataRecord dr) { string name = GetUTF8String(dr, "img_name"); uint size = DbUtils.Convert.To <uint>(dr["img_size"], 0); MimeType mimetype = new MimeType(GetUTF8String(dr, "img_major_mime") + "/" + GetUTF8String(dr, "img_minor_mime")); string changedescription = GetUTF8String(dr, "img_description"); uint userId; if (MediaWikiConverterContext.Current.Merge) { userId = MediaWikiConverterContext.Current.MergeUserId; } else { userId = DbUtils.Convert.To <uint>(dr["img_user"], 0); } // TODO (steveb): why is this not used?!? DateTime timestamp = DbUtils.ToDateTime(GetUTF8String(dr, "img_timestamp")); ResourceContentBE rc = new ResourceContentBE(true); rc.Size = size; rc.MimeType = mimetype; ResourceBE file = ResourceBL.Instance.BuildRevForNewResource(0 /*parent page defined later*/, ResourceBE.ParentType.PAGE, name, mimetype, size, changedescription, ResourceBE.Type.FILE, userId, rc); file.MetaXml.Elem("physicalfilename", GetUTF8String(dr, "img_filename")); return(file); }
public void Can_write_bytes_to_blank_BE() { var be = new ResourceContentBE(true); var v = 42; be.SetData(BitConverter.GetBytes(v)); Assert.AreEqual(v, BitConverter.ToInt32(be.ToBytes(), 0)); }
public void Can_create_BE_from_XDoc() { var doc = new XDoc("test").Elem("foo", StringUtil.CreateAlphaNumericKey(6)); var be = new ResourceContentBE(doc); var doc2 = XDocFactory.From(be.ToStream(), be.MimeType); Assert.AreEqual(doc, doc2); }
public ResourceBE UpdatePropertyContent(ResourceBE prop, ResourceContentBE content, string changeDescription, string eTag, AbortEnum abort, XUri parentUri, ResourceBE.ParentType parentType) { if (abort == AbortEnum.Modified) { _resourceBL.ValidateEtag(eTag, prop, true); } prop = _resourceBL.BuildRevForContentUpdate(prop, content.MimeType, content.Size, changeDescription, null, content); prop = _resourceBL.SaveResource(prop); DekiContext.Current.Instance.EventSink.PropertyUpdate(DekiContext.Current.Now, prop, DekiContext.Current.User, parentType, parentUri); return(prop); }
public void Can_create_BE_from_Stream() { var stream = new MemoryStream(); var bytes = Encoding.UTF8.GetBytes("foo"); stream.Write(bytes, 0, bytes.Length); stream.Position = 0; var be = new ResourceContentBE(stream, MimeType.TEXT_UTF8); Assert.AreEqual(MimeType.TEXT_UTF8, be.MimeType); Assert.AreEqual(stream.Length, be.Size); Assert.AreEqual(stream.Length, be.ToBytes().Length); }
private ResourceContentBE Resources_ContentInsert(ResourceContentBE contents) { string query = @" /* ResourceDA::ContentInsert */ insert into resourcecontents (rescontent_res_id, rescontent_res_rev, rescontent_location, rescontent_mimetype, rescontent_size, rescontent_value) values (?RESCONTENT_RES_ID, ?RESCONTENT_RES_REV, ?RESCONTENT_LOCATION, ?RESCONTENT_MIMETYPE, ?RESCONTENT_SIZE, ?RESCONTENT_VALUE); select last_insert_id();"; contents.ContentId = Catalog.NewQuery(query) .With("RESCONTENT_RES_ID", contents.ResourceId) .With("RESCONTENT_RES_REV", contents.Revision) .With("RESCONTENT_LOCATION", contents.Location) .With("RESCONTENT_MIMETYPE", contents.MimeType.ToString()) .With("RESCONTENT_SIZE", contents.Size) .With("RESCONTENT_VALUE", contents.IsDbBased ? contents.ToBytes() : null) .ReadAsUInt() ?? 0; return(contents); }
protected ResourceBE BuildRevForContentUpdate(ResourceBE currentResource, MimeType mimeType, uint size, string description, string name, ResourceContentBE newContent) { ResourceBE newRev = _resourceBL.BuildRevForContentUpdate(currentResource, mimeType, size, description, name, newContent); newRev.MetaXml.FileId = currentResource.MetaXml.FileId; return(newRev); }
public ResourceBE AddAttachment(ResourceBE existingRevision, Stream filestream, long filesize, MimeType mimeType, PageBE targetPage, string userDescription, string fileName, bool isMsWebDav) { if (_dekiContext.Instance.MaxFileSize < filesize) { throw new AttachmentMaxFileSizeAllowedInvalidArgumentException(_dekiContext.Instance.MaxFileSize); } var saveFileName = ValidateFileName(fileName); if (existingRevision != null) { if (!saveFileName.EqualsInvariant(existingRevision.Name)) { // An existing file is getting renamed. Make sure no file exists with the new name var existingAttachment = GetPageAttachment(targetPage.ID, saveFileName); if (existingAttachment != null) { throw new AttachmentExistsOnPageConflictException(saveFileName, targetPage.Title.AsUserFriendlyName()); } } } // If file is found but has been deleted, create a new file. if (existingRevision != null && existingRevision.ResourceIsDeleted) { existingRevision = null; } if (isMsWebDav) { _log.DebugFormat("Upload client is MD WebDAV, provided mimetype is: {0}", mimeType); var extensionFileType = MimeType.FromFileExtension(Path.GetExtension(saveFileName)); if (!extensionFileType.Match(mimeType) || extensionFileType == MimeType.DefaultMimeType) { mimeType = existingRevision == null ? extensionFileType : existingRevision.MimeType; _log.DebugFormat("using mimetype '{0}' instead", mimeType); } } ResourceBE attachment; var resourceContents = new ResourceContentBE((uint)filesize, mimeType); var isUpdate = false; if (existingRevision == null) { attachment = _resourceBL.BuildRevForNewResource((uint)targetPage.ID, ResourceBE.ParentType.PAGE, saveFileName, mimeType, (uint)filesize, null, ResourceBE.Type.FILE, _dekiContext.User.ID, resourceContents); } else { isUpdate = true; attachment = BuildRevForContentUpdate(existingRevision, mimeType, (uint)filesize, null, saveFileName, resourceContents); } // rewrite mimetype to text/plain for certain extensions string extension = attachment.FilenameExtension; if (_dekiContext.Instance.FileExtensionForceAsTextList.Any(forcedExtensions => extension == forcedExtensions)) { attachment.MimeType = MimeType.TEXT; } // Insert the attachment into the DB attachment = SaveResource(attachment); try { // Save file to storage provider _dekiContext.Instance.Storage.PutFile(attachment, SizeType.ORIGINAL, new StreamInfo(filestream, filesize, mimeType)); } catch (Exception x) { _dekiContext.Instance.Log.WarnExceptionFormat(x, "Failed to save attachment to storage provider"); // Upon save failure, delete the record from the db. _session.Resources_DeleteRevision(attachment.ResourceId, attachment.Revision); throw; } // Set description property if (!string.IsNullOrEmpty(userDescription)) { attachment = SetDescription(attachment, userDescription); } // For images resolve width/height (if not in imagemagick's blacklist) attachment = IdentifyUnknownImage(attachment); // Pre render thumbnails of images AttachmentPreviewBL.PreSaveAllPreviews(attachment); PageBL.Touch(targetPage, DateTime.UtcNow); //TODO MaxM: Connect with transaction RecentChangeBL.AddFileRecentChange(targetPage.Touched, targetPage, _dekiContext.User, DekiResources.FILE_ADDED(attachment.Name), 0); if (isUpdate) { _dekiContext.Instance.EventSink.AttachmentUpdate(_dekiContext.Now, attachment, _dekiContext.User); } else { _dekiContext.Instance.EventSink.AttachmentCreate(_dekiContext.Now, attachment, _dekiContext.User); } return(attachment); }
private ResourceContentBE Resources_ContentInsert(ResourceContentBE contents) { string query = @" /* ResourceDA::ContentInsert */ insert into resourcecontents (rescontent_res_id, rescontent_res_rev, rescontent_location, rescontent_mimetype, rescontent_size, rescontent_value) values (?RESCONTENT_RES_ID, ?RESCONTENT_RES_REV, ?RESCONTENT_LOCATION, ?RESCONTENT_MIMETYPE, ?RESCONTENT_SIZE, ?RESCONTENT_VALUE); select last_insert_id();"; contents.ContentId = Catalog.NewQuery(query) .With("RESCONTENT_RES_ID", contents.ResourceId) .With("RESCONTENT_RES_REV", contents.Revision) .With("RESCONTENT_LOCATION", contents.Location) .With("RESCONTENT_MIMETYPE", contents.MimeType.ToString()) .With("RESCONTENT_SIZE", contents.Size) .With("RESCONTENT_VALUE", contents.IsDbBased ? contents.ToBytes() : null) .ReadAsUInt() ?? 0; return contents; }
public ResourceBE Resources_SaveRevision(ResourceBE resource) { string query = string.Empty; bool contentUpdated = false; if (resource.Content != null && resource.Content.IsNewContent()) { contentUpdated = true; ResourceContentBE content = Resources_ContentInsert(resource.Content); resource.Content = content; resource.ContentId = content.ContentId; } if (resource.IsNewResource()) { query = @" /* Resources_SaveRevision (new resource) */ set @resourceid = 0; insert into resources set res_headrev = ?RES_HEADREV, res_type = ?RES_TYPE, res_deleted = ?RES_DELETED, res_create_timestamp = ?RES_CREATE_TIMESTAMP, res_update_timestamp = ?RES_UPDATE_TIMESTAMP, res_create_user_id = ?RES_CREATE_USER_ID, res_update_user_id = ?RES_UPDATE_USER_ID, resrev_rev = ?RESREV_REV, resrev_user_id = ?RESREV_USER_ID, resrev_parent_id = ?RESREV_PARENT_ID, resrev_parent_page_id = ?RESREV_PARENT_PAGE_ID, resrev_parent_user_id = ?RESREV_PARENT_USER_ID, resrev_change_mask = ?RESREV_CHANGE_MASK, resrev_name = ?RESREV_NAME, resrev_change_description = ?RESREV_CHANGE_DESCRIPTION, resrev_timestamp = ?RESREV_TIMESTAMP, resrev_content_id = ?RESREV_CONTENT_ID, resrev_deleted = ?RESREV_DELETED, resrev_changeset_id = ?RESREV_CHANGESET_ID, resrev_size = ?RESREV_SIZE, resrev_mimetype = ?RESREV_MIMETYPE, resrev_language = ?RESREV_LANGUAGE, resrev_is_hidden = ?RESREV_IS_HIDDEN, resrev_meta = ?RESREV_META; select last_insert_id() into @resourceid; insert into resourcerevs set resrev_res_id = @resourceid, resrev_rev = ?RESREV_REV, resrev_user_id = ?RESREV_USER_ID, resrev_parent_id = ?RESREV_PARENT_ID, resrev_parent_page_id = ?RESREV_PARENT_PAGE_ID, resrev_parent_user_id = ?RESREV_PARENT_USER_ID, resrev_change_mask = ?RESREV_CHANGE_MASK, resrev_name = ?RESREV_NAME, resrev_change_description = ?RESREV_CHANGE_DESCRIPTION, resrev_timestamp = ?RESREV_TIMESTAMP, resrev_content_id = ?RESREV_CONTENT_ID, resrev_deleted = ?RESREV_DELETED, resrev_changeset_id = ?RESREV_CHANGESET_ID, resrev_size = ?RESREV_SIZE, resrev_mimetype = ?RESREV_MIMETYPE, resrev_language = ?RESREV_LANGUAGE, resrev_is_hidden = ?RESREV_IS_HIDDEN, resrev_meta = ?RESREV_META; update resourcecontents set rescontent_res_id = @resourceid, rescontent_res_rev = ?RESREV_REV where rescontent_id = ?RESREV_CONTENT_ID; select * from resources left join resourcecontents on resources.resrev_content_id = resourcecontents.rescontent_id where res_id = @resourceid; /* End of ResourceDA::InsertResourceRevision (new resource) */ "; } else { resource.Revision = ++resource.ResourceHeadRevision; if (contentUpdated) { resource.Content.Revision = (uint)resource.Revision; } query = @" /* Resources_SaveRevision + concurrency check (new revision) */ update resources set res_headrev = ?RES_HEADREV, res_type = ?RES_TYPE, res_deleted = ?RES_DELETED, res_update_timestamp = ?RESREV_TIMESTAMP, res_update_user_id = ?RES_UPDATE_USER_ID, resrev_rev = ?RESREV_REV, resrev_user_id = ?RESREV_USER_ID, resrev_parent_id = ?RESREV_PARENT_ID, resrev_parent_page_id = ?RESREV_PARENT_PAGE_ID, resrev_parent_user_id = ?RESREV_PARENT_USER_ID, resrev_change_mask = ?RESREV_CHANGE_MASK, resrev_name = ?RESREV_NAME, resrev_change_description = ?RESREV_CHANGE_DESCRIPTION, resrev_timestamp = ?RESREV_TIMESTAMP, resrev_content_id = ?RESREV_CONTENT_ID, resrev_deleted = ?RESREV_DELETED, resrev_changeset_id = ?RESREV_CHANGESET_ID, resrev_size = ?RESREV_SIZE, resrev_mimetype = ?RESREV_MIMETYPE, resrev_language = ?RESREV_LANGUAGE, resrev_is_hidden = ?RESREV_IS_HIDDEN, resrev_meta = ?RESREV_META WHERE res_id = ?RES_ID AND res_headrev = ?RES_HEADREV - 1 AND res_update_timestamp = ?RES_UPDATE_TIMESTAMP; select ROW_COUNT() into @affectedRows; select * from resources where @affectedrows > 0 and res_id = ?RES_ID; "; if (ArrayUtil.IsNullOrEmpty(Resources_ExecuteInsertUpdateQuery(resource, query))) { //Cleanup content row if resource could not be updated Resources_ContentDelete(resource.ContentId); throw new ResourceConcurrencyException(resource.ResourceId); } query = @" /* Resources_SaveRevision (new revision) */ replace into resourcerevs set resrev_res_id = ?RES_ID, resrev_rev = ?RESREV_REV, resrev_user_id = ?RESREV_USER_ID, resrev_parent_id = ?RESREV_PARENT_ID, resrev_parent_page_id = ?RESREV_PARENT_PAGE_ID, resrev_parent_user_id = ?RESREV_PARENT_USER_ID, resrev_change_mask = ?RESREV_CHANGE_MASK, resrev_name = ?RESREV_NAME, resrev_change_description = ?RESREV_CHANGE_DESCRIPTION, resrev_timestamp = ?RESREV_TIMESTAMP, resrev_content_id = ?RESREV_CONTENT_ID, resrev_deleted = ?RESREV_DELETED, resrev_changeset_id = ?RESREV_CHANGESET_ID, resrev_size = ?RESREV_SIZE, resrev_mimetype = ?RESREV_MIMETYPE, resrev_language = ?RESREV_LANGUAGE, resrev_is_hidden = ?RESREV_IS_HIDDEN, resrev_meta = ?RESREV_META; update resourcecontents set rescontent_res_id = ?RES_ID, rescontent_res_rev = ?RESCONTENT_RES_REV where rescontent_id = ?RESREV_CONTENT_ID; select * from resources left join resourcecontents on resources.resrev_content_id = resourcecontents.rescontent_id where res_id = ?RES_ID; "; } ResourceBE[] ret = Resources_ExecuteInsertUpdateQuery(resource, query); return((ArrayUtil.IsNullOrEmpty(ret)) ? null : ret[0]); }
public virtual ResourceBE BuildRevForContentUpdate(ResourceBE currentResource, MimeType mimeType, uint size, string description, string name, ResourceContentBE newContent) { ResourceBE newRev = BuildRevForExistingResource(currentResource, mimeType, size, description); newRev.Content = newContent; newRev.ContentId = 0; newRev.ChangeMask |= ResourceBE.ChangeOperations.CONTENT; if (name != null && !StringUtil.EqualsInvariant(name, newRev.Name)) { newRev.ChangeMask |= ResourceBE.ChangeOperations.NAME; newRev.Name = name; } return(newRev); }
private ResourceBE BuildRevForNewResource(string resourcename, MimeType mimeType, uint size, string description, ResourceBE.Type resourceType, uint userId, ResourceContentBE content) { ResourceBE newResource = new ResourceBE(resourceType); newResource.Name = resourcename; newResource.ChangeMask = newResource.ChangeMask | ResourceBE.ChangeOperations.NAME; newResource.Size = size; newResource.MimeType = mimeType; newResource.ChangeDescription = description; newResource.ResourceCreateUserId = newResource.ResourceUpdateUserId = newResource.UserId = userId; newResource.ChangeSetId = 0; newResource.Timestamp = newResource.ResourceCreateTimestamp = newResource.ResourceUpdateTimestamp = DateTime.UtcNow; newResource.Content = content; newResource.ChangeMask = newResource.ChangeMask | ResourceBE.ChangeOperations.CONTENT; newResource.ResourceHeadRevision = ResourceBE.TAILREVISION; newResource.Revision = ResourceBE.TAILREVISION; newResource.IsHidden = false; return(newResource); }
public virtual ResourceBE BuildRevForNewResource(uint?parentId, ResourceBE.ParentType parentType, string resourcename, MimeType mimeType, uint size, string description, ResourceBE.Type resourceType, uint userId, ResourceContentBE content) { ResourceBE newResource = BuildRevForNewResource(resourcename, mimeType, size, description, resourceType, userId, content); switch (parentType) { case ResourceBE.ParentType.PAGE: newResource.ParentPageId = parentId; break; case ResourceBE.ParentType.USER: newResource.ParentUserId = parentId; break; default: newResource.ParentId = parentId; break; } newResource.ChangeMask = newResource.ChangeMask | ResourceBE.ChangeOperations.PARENT; return(newResource); }
public ResourceBE[] SaveBatchProperties(uint?parentId, XUri parentUri, ResourceBE.ParentType parentType, XDoc doc, out string[] failedNames, out Dictionary <string, Exception> saveStatusByName) { //This is a specialized method that saves a batch of property updates in one request and connects them with a transaction. //Successful updates are returned //Status/description of each property update is returned as well as a hash of dreammessages by name saveStatusByName = new Dictionary <string, Exception>(); List <string> failedNamesList = new List <string>(); Dictionary <string, ResourceBE> resourcesByName = new Dictionary <string, ResourceBE>(); List <ResourceBE> ret = new List <ResourceBE>(); //Get list of names and perform dupe check foreach (XDoc propDoc in doc["/properties/property"]) { string name = propDoc["@name"].AsText ?? string.Empty; if (resourcesByName.ContainsKey(name)) { throw new PropertyDuplicateInvalidOperationException(name); } resourcesByName[name] = null; } //Retrieve current properties with given name resourcesByName = _resourceBL.GetResources(parentId, parentType, ResourceBL.PROPERTIES, new List <string>(resourcesByName.Keys).ToArray(), DeletionFilter.ACTIVEONLY).AsHash(e => e.Name); //extract property info, build resource revisions, save resource, and maintain statuses for each save foreach (XDoc propDoc in doc["/properties/property"]) { ResourceBE res = null; string content; uint contentLength = 0; string description = string.Empty; string etag = null; MimeType mimeType; string name = string.Empty; try { name = propDoc["@name"].AsText ?? string.Empty; resourcesByName.TryGetValue(name, out res); if (propDoc["contents"].IsEmpty) { if (res == null) { throw new PropertyDeleteDoesNotExistInvalidArgumentException(name); } else { res = DeleteProperty(res, parentType, parentUri); } } else { //parse content from xml etag = propDoc["@etag"].AsText; description = propDoc["description"].AsText; content = propDoc["contents"].Contents; contentLength = (uint)(content ?? string.Empty).Length; string mimeTypeStr = propDoc["contents/@type"].AsText; if (string.IsNullOrEmpty(mimeTypeStr) || !MimeType.TryParse(mimeTypeStr, out mimeType)) { throw new PropertyMimtypeInvalidArgumentException(name, mimeTypeStr); } ResourceContentBE resourceContent = new ResourceContentBE(content, mimeType); if (res == null) { //new property res = CreateProperty(parentId, parentUri, parentType, name, resourceContent, description, etag, AbortEnum.Exists); } else { //new revision res = UpdatePropertyContent(res, resourceContent, description, etag, AbortEnum.Modified, parentUri, parentType); } } ret.Add(res); saveStatusByName[name] = null; } catch (ResourcedMindTouchException x) { //Unexpected errors fall through while business logic errors while saving a property continues processing saveStatusByName[name] = x; failedNamesList.Add(name); } catch (DreamAbortException x) { // TODO (arnec): remove this once all usage of DreamExceptions is purged from Deki logic //Unexpected errors fall through while business logic errors while saving a property continues processing saveStatusByName[name] = x; failedNamesList.Add(name); } } failedNames = failedNamesList.ToArray(); return(ret.ToArray()); }
public ResourceBE CreateProperty(uint?parentId, XUri parentUri, ResourceBE.ParentType parentType, string name, ResourceContentBE content, string description, string etag, AbortEnum abort) { //TODO: The parent resource isn't verified when the resource name and the parent info is given ResourceBE prop = _resourceBL.GetResource(parentId, parentType, ResourceBE.Type.PROPERTY, name, DeletionFilter.ACTIVEONLY); if (prop != null) { switch (abort) { case AbortEnum.Exists: throw new PropertyExistsConflictException(name); case AbortEnum.Modified: _resourceBL.ValidateEtag(etag, prop, true); break; } prop = _resourceBL.BuildRevForContentUpdate(prop, content.MimeType, content.Size, description, null, content); prop = _resourceBL.SaveResource(prop); DekiContext.Current.Instance.EventSink.PropertyUpdate(DekiContext.Current.Now, prop, DekiContext.Current.User, parentType, parentUri); } else { if ((abort == AbortEnum.Modified) && !string.IsNullOrEmpty(etag)) { throw new PropertyUnexpectedEtagConflictException(); } prop = _resourceBL.BuildRevForNewResource(parentId, parentType, name, content.MimeType, content.Size, description, ResourceBE.Type.PROPERTY, DekiContext.Current.User.ID, content); prop = _resourceBL.SaveResource(prop); DekiContext.Current.Instance.EventSink.PropertyCreate(DekiContext.Current.Now, prop, DekiContext.Current.User, parentType, parentUri); } return(prop); }