Media file size report in Umbraco - umbraco

I have a lot of images in the Media section of the CMS. I was wondering what the best way to get a list of the images and their file sizes were?
Would manipulating the xml string in the db be better or adding a column in the CMS front end?

UPDATED ANSWER:
Faster and better recursive solution:
<ul id="imageList">
#foreach (var item in Umbraco.TypedMediaAtRoot()) {
#ShowMediaItems(item)
}
</ul>
#helper ShowMediaItems(IPublishedContent media) {
if (media.Descendants().Any(p => p.DocumentTypeAlias != "Folder") && media.DocumentTypeAlias == "Folder") {
<ul>
#foreach (var child in media.Children) {
#ShowMediaItems(child)
}
</ul>
} else if (media.DocumentTypeAlias == "Image") {
<li>Image url: #media.Url - Size: #(media.GetPropertyValue<int>("umbracoBytes"))</li>
}
}
It will go as deep as it has to and is much faster. I've put a new ul list for each level, but you can get rid of it.
ORIGINAL ANSWER:
This works and it will be slow when dealing with a lot of images but if you need to get a list for yourself (as in a one time thing), then it should do the job:
<ul>
#foreach (var item in Umbraco.TypedMediaAtRoot())
{
//Level 1
if (item.DocumentTypeAlias == "Folder")
{
//Level 2
foreach (var item2 in Umbraco.TypedMedia(item.Id).Children)
{
if (item2.DocumentTypeAlias == "Folder")
{
//Level 3
foreach (var item3 in Umbraco.TypedMedia(item2.Id).Children)
{
if (item3.DocumentTypeAlias == "Folder")
{
//Level 3
//etc..
}
else if (item3.DocumentTypeAlias == "Image")
{
<li>Image url: #item3.Url - Size: #(item3.GetPropertyValue<int>("umbracoBytes"))</li>
}
}
}
else if (item2.DocumentTypeAlias == "Image")
{
<li>Image url: #item2.Url - Size: #(item2.GetPropertyValue<int>("umbracoBytes"))</li>
}
}
}
else if (item.DocumentTypeAlias == "Image")
{
<li>Image url: #item.Url - Size: #(item.GetPropertyValue<int>("umbracoBytes"))</li>
}
}
</ul>
You can go as deep as you prefer depending on how many folders you've got in your media section.
See comments in the code. Level 1 is the root media folder, Level 2 is a folder that is under the root and so on.
I've just tested it on my local Umbraco instance and it works.
Regarding the sizes, they come as bytes, so you can do your own calculation using the GetPropertyValue("umbracoBytes")

Related

How to update existing rows using Entity Framework?

I have the following one to many table as below. I am experiencing issue when it comes to editing the existing rows with the following code. Please understand that I am pretty new to the ET relationship, so any detailed explanation would be greatly appreciated. Why it is returning null values?
public void UpdateReportGroup(TReportHeaderModel model)
{
if (model.THeaderTitle == null)
{
throw new Exception("Report Group Title must be filled in");
}
if (model.THeaderTitle.Length <= 0)
{
throw new Exception("A Report Group Title must be filled in.");
}
using (var connection = new TReportEntitiesConnection())
{
var header = connection.THeaders.SingleOrDefault(f => f.ID == model.ID);
var reports = connection.TReport.Where(f => f.THeaderID == model.ID);
connection.TReport.RemoveRange(reports);
foreach (var urls in model.TReports)
{
connection.TReport.Add(new TReport()
{
TReportName = urls.name,
URL = urls.url,
});
}
connection.THeaders.Add(header);
connection.SaveChanges()
}
}
Everytime, I debug it,it is giving null values for the 'TReport' table.
My create new rows works perfectly with the following code. Meaning, I am returning the correct form with correct field names.
public void CreateReport(TReportHeaderModel model)
{
if (model.THeaderTitle == null)
{
throw new Exception("Report Group Title must be filled in");
}
if (model.THeaderTitle.Length <= 0)
{
throw new Exception("A Report Group Title must be filled in.");
}
using (var connection = new TReportEntitiesConnection())
{
var header = new THeader()
{
ClientID = model.ClientID,
THeaderTitle = model.THeaderTitle,
RowNumber = model.RowNumber
};
foreach (var urls in model.TReports)
{
header.TReports.Add(new TReport()
{
TReportName = urls.name,
URL = urls.url
});
}
connection.THeaders.Add(header);
connection.SaveChanges();
}
}
As you can see, I am following DI pattern, and therefore I am calling these two methods in my controller as below:
[HttpPost]
public ActionResultModel CreateReportAPI([FromBody] TReportHeaderModel model) //attempt 3
{
try {
if (ModelState.IsValid)
{
var isValid = _tReportingService.HeadernameExists(model.THeaderTitle);
if (!isValid)
{
Console.WriteLine("it does not exist");
var user = this.GetCurrentUserAccount();
model.ClientID = user.SelectedClient.ID;
_tReportingService.CreateReport(model);
}
else //Update method comes till here and it goes //straight to the error
{
Console.WriteLine("it exists");
var user = this.GetCurrentUserAccount();
model.ClientID = user.SelectedClient.ID;
_tReportingService.UpdateReportGroup(model);
}
}
return new ActionResultModel()
{
Success=true,
Message="Report Group Successfully Saved."
};
}
I guess it would be the last time I'd posting questions here as I understood that it takes you nowhere if you just ask so I'd rather research more and keep trying it until I got it so here I am answering my own question as I'd solved it.
As the model gets generated from WebApi which is completely detached from ET, I am loading the database first and compare which children have been added, deleted & updated. Here is an example of perfect one to many relationship's update/delete.
using (var connection = new TReportEntitiesConnection())
{
var header = connection.THeaders.Include("TReports").SingleOrDefault(f => f.ID == model.ID);
if (header != null)
{
header.THeaderTitle = model.THeaderTitle; //update parent
}
foreach (var existingChild in header.TReports.ToList())
{
if (!model.TReports.Any(c => c.ID == existingChild.ID))
connection.TReport.Remove(existingChild);
}
foreach (var url in model.TReports)
{
var existingChild = header.TReports
.Where(c => c.ID == url.ID)
.SingleOrDefault();
if (existingChild != null)
{ //update child
connection.Entry(existingChild).CurrentValues.SetValues(url);
}
else
{
var newChild = new TReport
{
TReportName = url.name,
URL = url.url,
};
header.TReports.Add(newChild);
}
}
connection.SaveChanges();
}

Assign Path for each link in ASP MVC

I have multiple pdf documents that I have to show in a view .My code is opening the same document for all the links which is wrong.
In my contoller :
public ActionResult Docs()
{
var docModel = this._documentBuilder.Build(this.StateData);
foreach (var doc in docModel.OldEstimateFiles)
{
return this.File(doc.PdfUrl, "application/pdf");
}
return null;
}
and in the view :
foreach (var menuItem in Model.OldEstimateFiles)
{
<ul >
<li>
#using (Html.Anchor(new ststyle { URL = "/DocumentEstimate/Docs", Target = "_blank", Text = menuItem.Label }))
{
}
</li>
</ul>
}
what is wrong in my code knowing that oldestimatefiles is a list
I edited my action in the controller to take in the ID.
public ActionResult Docs(string id)
{
var docModel = this._documentBuilder.Build(this.StateData);
return docModel.OldEstimateFiles.Any() ? this.File(docModel.OldEstimateFiles.Find(p => p.ID == id).PdfUrl, "application/pdf") : null;
}
I added an entry in the routeConfig file taking in the URL the id of the document and In the view I edited my link :
#using (Html.Anchor(new ststyle
{
URL = "/DocumentEstimate/EstimateDocs/" + menuItem.ID,
Id = menuItem.ID
It resolved the issue.

How to write a custom `#Html.Partial()` method in ASP.NET MVC?

I need to create a custom #Html.Partial() method.
Use Case
I have a .cshtml page where in I have multple sections like below
<!-- EDUCATION -->
#Html.Partial("Templates/Create/Modules/Education")
<!-- JOBS -->
#Html.Partial("Templates/Create/Modules/Jobs")
I want to be able to create a custom .Partial() method. Something on the likes of this
#Html.CustomPartial("Templates/Create/Modules/Jobs", "jobs", "edit")
where in the last two parameters are module id and action type id respectively. Using these values I will make a decision in my CustomPartial what I need to show in the output.
I am not sure how to go about this one. Please advice.
Or if someone can point me to the source code of the Html.Partial that too would be very helpful.
You can already do this using the overload of #Html.Partial() that accepts a ViewDataDictionary
#Html.Partial("Templates/Create/Modules/Jobs", new ViewDataDictionary { { "module", someValue }, {"edit", anotherValue }})
Then in the partial
#if(ViewData["module"] == someValue)
{
// do something
}
else
{
// do something else
}
And if your still interested, here is the source code
Here is what worked for me
public static class CustomHtmlHelpers
{
public static MvcHtmlString RenderModule(this HtmlHelper helper,
string partialViewName,
string moduleName,
string actionType)
{
var isAccessAllowed = _someService.someMethod(userId, moduleName, actionType);
if (isAccessAllowed)
{
return helper.Partial(partialViewName);
}
else
{
return MvcHtmlString.Empty;
}
}
}
#Html.Partial("../Partial_views/_Menu_creation", new ViewDataDictionary { { "Type",
"Menu" }, { "Menu", "Dimensions" }, { "Active", "Yes" }, { "Icon", "icon-1" }, {
"data-hide", "" } })
In partial view
#if (ViewData["Type"] == "Menu")
{
#if (ViewData["Active"] == "Yes")
{
<a data-check='#ViewData["Menu"]' role="button" class="active-menu">
<b class='#ViewData["Icon"]'></b>
<span>#ViewData["Menu"]</span>
</a>
}
else
{
}
}
#if (ViewData["Type"] == "Heading")
{
}
This is working

Sequence contains no elements errror - MVC (Models and Data Access)

I'm trying to follow the MVC Music Store tutorial , but I got an error which I can't handle. I've created the action:
public ActionResult Browse(string category)
{
using (OnlineStoreDbContext db = new OnlineStoreDbContext())
{
// Get category and its associated products
var categoryModel = db.Categories.Include("Products")
.Single(c => c.Title == category);
return View(categoryModel);
}
}
Than I created and the respective View:
#model OnlineStoreMVC.Core.Models.Category
#{
ViewBag.Title = "Browse";
}
<h2>Browse Category: #Model.Title</h2>
<ul>
#foreach (var product in Model.Products)
{
<li>
#product.Title
</li>
}
</ul>
But when I try to open: http://localhost:51642/Store/Browse?cat=Action, I get error:
"Sequence contains no elements" regarding this line:
var categoryModel = db.Categories.Include("Products")
.Single(c => c.Title == category);
I've alredy tried to replace Single with SingleOrDefault, but then the error was
"Object reference not set to an instance of an object." regarding that line in the View: "<h2>Browse Category: #Model.Title</h2>"
The problem is that you're passing cat as key in you're url and it should be category. So you should call http://localhost:51642/Store/Browse?category=Action
About the the error "Object reference not set to an instance of the object" you have to change you Action method to:
public ActionResult Browse(string category)
{
using (OnlineStoreDbContext db = new OnlineStoreDbContext())
{
// Get category and its associated products
var categoryModel = db.Categories.Include("Products")
.SingleOrDefault(c => c.Title == category);
if (categoryModel == default(Category))
{
categoryModel = new Category();
categoryModel.Products = new List<Product>();
}
return View(categoryModel);
}
}

Can I make the razor syntax simpler

I have the following:
#if ((#Model.SeqId != 0) & (Model.SeqId != 1))
{
<text>
window.location.href = "www.stackoverflow.com";
</text>
}
I don't know much about razor. Is there something I could do to make it simpler?
Yes, you can. Suffice to define a property on your view model
public bool ShouldRedirectToSO
{
get
{
return (SeqId != 0 && SeqId != 1);
}
}
and then:
<script type="text/javascript">
#if (Model.ShouldRedirectToSO)
{
#:window.location.href = 'http://www.stackoverflow.com';
}
</script>
or if you intend to redirect immediately on page load if the condition is met you could also do this directly from the controller:
public ActionResult Foo()
{
var model = ...
if (model.ShouldRedirectToSO)
{
return Redirect("http://www.stackoverflow.com");
}
return View(model);
}
Can SeqId ever be less than 0? If not, you could do
#if (Model.SeqId > 1)
{
<text>
window.location.href = "www.stackoverflow.com";
</text>
}
Also, you don't need to # the Model in a code block. You probably want to use && instead of & as this fails as soon as the first test is false, saves a few CPU cycles.
http://msdn.microsoft.com/en-us/library/2a723cdk(v=vs.71).aspx

Resources