I have a Folder Doc Type in content and i'd like it to create a matching folder in Media. I've hooked into the ContentService.Saved method so I have access to when my folder is created.
What would be the best way to try and match this to creating a media item? I was thinking of checking through all media items and if they have the same name as the content parent and are created within a minute of each other using that as the media parent (so folders can be nested) but that sounds expensive in terms of performance
I'm unsure how either of these could be used to create a matching Media folder. A relation seems to map the 2 items together but not create, and a media picker property would give me the tool to make the folder but would still need to be manually created.
Maybe i'm wrong with Relation, could you give me an example?
We had to this recently on a website we built storm models. So in the content section each model node exists as a talent node type. When you create and save one of these we tap into the saved event then in media section under models media folder do a search for folder with same model name if it does not exist then we create it.
The id of newly created media folder we store in text field in attributes tab on content node. If on save we have this idea then just get the folder directly using that id. So from performance perspective you potentially have over head first but subsequently you will not because you have an id. Also we use that idea for media pickers on talent node so that when you click to pick the media folder start is already set to the talents media folder makes for a better ui experience for editors.
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.UI;
using Constants = Constants.Constants;
namespace Application.BusinessLogic.Handlers
{
/// <summary>
/// this handler which intercepts webapi calls is wired up in UmbracoEvents.Applicationstarting
/// listens out for umbraco content api web requests
/// code taken from https://github.com/jbreuer/Hybrid-Framework-for-Umbraco-v7-Best-Practises/blob/master/Umbraco.Extensions/Utilities/WebApiHandler.cs
/// with some modifications
/// </summary>
public class WebApiHandler : System.Net.Http.DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
switch (request.RequestUri.AbsolutePath.ToLower())
{
case "/umbraco/backoffice/umbracoapi/content/postsave":
case "/umbraco/backoffice/umbracoapi/content/getbyid":
return SetContentMediaPickerStartNode(request, cancellationToken);
default:
return base.SendAsync(request, cancellationToken);
}
}
/// <summary>
/// each talent has a related media picker folder, we want to set id dynamically so we pick images from correct folder
/// </summary>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private Task<HttpResponseMessage> SetContentMediaPickerStartNode(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
try
{
//Get the content that we want to modify.
var data = response.Content;
var content = ((ObjectContent)(data)).Value as ContentItemDisplay;
//we only want to do this for talent items
if (Constants.TalentDocTypes.Contains(content.ContentTypeAlias))
{
SetMediaPickerStartNode(content.Properties);
}
}
catch (Exception ex)
{
LogHelper.Error<WebApiHandler>("Could not change the media picker start node.", ex);
}
return response;
}
);
}
/// <summary>
/// for the current item which is a model type set all the media pickers
/// start folder to associated media folder in media section id of it is set in
/// the properties tab, NB if we need to have media folders that should not start
/// in talents media folder then you need to exclude that folder
/// </summary>
/// <param name="properties"></param>
private void SetMediaPickerStartNode(IEnumerable<ContentPropertyDisplay> properties)
{
//Get the media pickers which we want to change the start node from.
var mediaPickers = properties.Where(x =>
Umbraco.Core.Constants.PropertyEditors.MediaPickerAlias.InvariantEquals(x.Editor) ||
Umbraco.Core.Constants.PropertyEditors.MultipleMediaPickerAlias.InvariantEquals(x.Editor)
).ToList();
//check that the current doc has got startNodeId property
var startIdProperty =
properties.FirstOrDefault(x => Umbraco.Core.Constants.PropertyEditors.TextboxAlias.InvariantEquals(x.Editor) &&
x.Alias == Constants.DocTypesProperties.Talent.MediaStartNodeId);
//ensure we have media pickers and we have a media folder start id
if (mediaPickers.Any() && HaveMediaFolder(startIdProperty))
{
var startId = startIdProperty.Value.ToString();
foreach (var mediaPicker in mediaPickers)
{
mediaPicker.Config[Constants.MediaPickerStartNodeAlias] = startId;
}
}
}
/// <summary>
/// ensure we have an id for media folder and that it exists
/// it may be that its been deleted
/// </summary>
/// <param name="startIdProperty"></param>
/// <returns></returns>
private bool HaveMediaFolder(ContentPropertyDisplay startIdProperty)
{
if(startIdProperty!=null && !string.IsNullOrEmpty(startIdProperty.Value.ToString()))
{
int mediaFolderId = 0;
bool haveId = int.TryParse(startIdProperty.Value.ToString(), out mediaFolderId);
if (haveId)
{
var mediaFolder = ApplicationContext.Current.Services.MediaService.GetById(mediaFolderId);
if (mediaFolder != null && mediaFolder.Id != 0)
{
return true;
}
}
}
return false;
}
}
I've tried implementing the media picker start node, but i'm having the problem of it not working. I have it finding my media node id and running in the correct places which is great.
Is mediaPicker.Config[Constants.MediaPickerStartNodeAlias] something that interacts with the hybrid framework and not in Umbraco by default? If not what is the hardcoded string, or is there a way to implement it that wouldn't be starting again and integrating this framework?
Create Matching Media Folder with Content Folder
Hello,
I have a Folder Doc Type in content and i'd like it to create a matching folder in Media. I've hooked into the ContentService.Saved method so I have access to when my folder is created.
What would be the best way to try and match this to creating a media item? I was thinking of checking through all media items and if they have the same name as the content parent and are created within a minute of each other using that as the media parent (so folders can be nested) but that sounds expensive in terms of performance
Any help would be appreciated
Hi Fred,
You could create a Relation between the two. Or have a media picker property on the document type that points to the media folder.
Hi Steven,
I'm unsure how either of these could be used to create a matching Media folder. A relation seems to map the 2 items together but not create, and a media picker property would give me the tool to make the folder but would still need to be manually created.
Maybe i'm wrong with Relation, could you give me an example?
Fred,
We had to this recently on a website we built storm models. So in the content section each model node exists as a talent node type. When you create and save one of these we tap into the saved event then in media section under models media folder do a search for folder with same model name if it does not exist then we create it.
The id of newly created media folder we store in text field in attributes tab on content node. If on save we have this idea then just get the folder directly using that id. So from performance perspective you potentially have over head first but subsequently you will not because you have an id. Also we use that idea for media pickers on talent node so that when you click to pick the media folder start is already set to the talents media folder makes for a better ui experience for editors.
Regards
Ismail
Hi Ismail,
That sounds exactly what I need. Out of interest, how did you get the media picker to start at a node, as that was on my todo also
Cheers, Fred
Fred,
I nicked some code from the excellent mvc hybrid project see https://our.umbraco.org/projects/developer-tools/hybrid-framework-for-umbraco-v7/ and the actual code https://github.com/jbreuer/Hybrid-Framework-for-Umbraco-v7-Best-Practises/blob/master/Umbraco.Extensions/Utilities/WebApiHandler.cs so it was using this class and my code looks like
using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.UI; using Constants = Constants.Constants;
namespace Application.BusinessLogic.Handlers {
}
Alright brilliant, Thanks alot!
Hi Ismail,
I've tried implementing the media picker start node, but i'm having the problem of it not working. I have it finding my media node id and running in the correct places which is great.
Is mediaPicker.Config[Constants.MediaPickerStartNodeAlias] something that interacts with the hybrid framework and not in Umbraco by default? If not what is the hardcoded string, or is there a way to implement it that wouldn't be starting again and integrating this framework?
Thanks, Fred
Fred,
Replace Constants.MediaPickerStartNodeAlias with your field alias that has the node id. That bit of code is specific to my situation.
Regards
Ismail
Hi Ismail, the problem was i called it StartNodeId when it's startNodeId...
anyway thank you again it's all working perfectly now, you rock!
Fred
Hi Ismail,
Is there anyway to have it list ancestor nodes so users can still navigate?
it currently just says my folder name but i'd like it to be
root/folder/myfolder so users can still decide where they'd like it uploaded to.
Thanks, Fred
Fred,
Don't think so, I have only used it where I need child folders.
Regards
Ismail
is working on a reply...