Is there a way to add count limitations to the content tab nodes?
For example you have following node structure:
Home
|
|-- About
|
|-- Projects
|
|-- Project 1
|
|-- Project 2
|
|-- News
|
|-- News 1
|
|-- News 2
|
|
...
Customer 1:
Chooses the standard hosting package and gets 10 projects and 10 news items.
Customer 2:
Chooses the ultimate hosting package and gets 1000 projects and 1000 news items.
How can I limit the customer to only create up to a certain projects and newsitems?
You could hook into the Umbraco Application Event Handler to catch the ContentService.Created event (the ContentService.Creating event is obsolete since it offers the same options).
public class AppEvents : IApplicationEventHandler
{
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ContentService.Created += ContentService_Creating;
}
}
Then you could write an extension to the Created event that would check the type of page being created and apply restrictions according to the current user's UserType. This would just mean that you cancel the event and prevent the page from being created.
public void ContentService_Creating(IContentService sender, Umbraco.Core.Events.NewEventArgs<IContent> e)
{
switch (e.Entity.ContentType.Alias)
{
case "ProjectAlias":
case "NewsItemAlias":
var contentService = Umbraco.Web.UmbracoContext.Current.Application.Services.ContentService;
var userTypeAlias = UmbracoContext.Current.Security.CurrentUser.UserType.Alias;
var count = contentService.GetChildren(e.Entity.ParentId).Count();
if (string.Equals(userTypeAlias, "Standard") && count >= 10)
{
e.Cancel = true;
}
else if (string.Equals(userTypeAlias, "Ultimate") && count >= 1000)
{
e.Cancel = true;
}
break;
default:
break;
}
}
This is untested but I've used similar methods before to prevent pages from being created/deleted by certain users.
I recommend that you use the package NodeRestrict.
You can specify through a config file the maximum nodes a user can create under a parent node. E.g. For your case:
<?xml version="1.0" encoding="utf-8" ?>
<nodeRestrict propertyAlias="maxChildNodes" showWarnings="false">
<rule
parentDocType="News"
childDocType="NewsChild"
maxNodes="10"
showWarnings="true"
customMessage=""
customMessageCategory=""
customWarningMessage=""
customWarningMessageCategory=""
>
</rule>
</nodeRestrict>
Related
I have an Android UI layout that is rather complex (it has a lot added to it dynamically depending on business rules).
One part of the UI has a LinearLayout which contains another layout which contains an EditText. Sometimes there is another LinearLayout in the base layout with the edit text in - it looks like this
LinearLayout
|
+-EditText
|
+-LinearLayout
| |
| +-EditText
+-EditText
|
+-LinearLayout
| |
| +-LinearLayout
| | |
| | +-EditText
| +-EditText
And so on
Currently, I have a pile of loops in a method that check if it's LinearLayout, then checks if the next Child is an EditText or a LinearLayout. If it's another LinearLayout then it creates another loop, checks if there is an EditText and so on. It gets messy.
Is there a way in LINQ (or something similar) that I can iterate through an entire LinearLayout in order to pick out the EditText widgets?
I don't know of a way in LINQ as you've requested, and am not sure how you're looping in code, but a few years back I had a similar need, and created a class that will iterate every view, including deeply nested views.
The output string displays the full hierarchy, including children, grandchildren, etc. with appropriate indentations. Of course, you can modify the code to look for a specific view type and act on it, such as:
if (vChild is EditText) vChild.Enabled = false;
Hope this helps!
public class IterateView {
// Iterate a view and all children recursively and generate a visual hierarchy
#region Example Usage
// //OnCreate()...
// SetContentView(Resource.Layout.MyLayout);
// RelativeLayout view = FindViewById<RelativeLayout>(Resource.Id.MyRelativeLayoutView);
// IterateView iv = new IterateView();
// iv.Iterate(view);
// string s = iv.OutputString;
#endregion
private readonly StringBuilder sb = new StringBuilder();
private const string PADDING_STRING = " ";
private string sPadding = "";
public string OutputString { get; private set; }
public void Iterate(View view) {
if (view is ViewGroup)
IterateViewChildren(view);
else
sb.AppendLine(sPadding + view.GetType().Name);
OutputString = sb.ToString();
}
private void IterateViewChildren(View view) {
if (view is ViewGroup) {
sb.AppendLine(sPadding + view.GetType().Name + " (ViewGroup)");
sPadding += PADDING_STRING;
ViewGroup vGroup = (ViewGroup)view;
for (int i = 0; i < vGroup.ChildCount; i++) {
if (!(vGroup.GetChildAt(i) is ViewGroup))
sb.AppendLine(sPadding + vGroup.GetChildAt(i).GetType().Name);
View vChild = vGroup.GetChildAt(i);
IterateViewChildren(vChild);
}
// Remove padding after iterating children to get us back to where we need to be
sPadding = sPadding.Remove(sPadding.Length - PADDING_STRING.Length);
}
}
}
I am in doubt about how to implement the Web API Routing when you have multiple DTOs for the same POCO.
Let us imagine the following scenario:
you have a POCO Class with. Let's say 100 properties
you need to display lists of that class in different platforms/UIs
i.e.
List 1 Prop A1 | Prop A2 | Prop A3 | Prop A4
List 2 Prop A21 | Prop A22 | Prop A23 | Prop A24 | Prop A25 | Prop A26 | Prop A27 | Prop A28 |
I will call it Company, since there are many examples using this class name
Is it correct to implement a Web API + DTOs strategy like this?
Classes are:
Company (the POCO class)
CompanyDetailDTO
CompanyLightListDTO
CompanyMediumListDTO
Example:
public class CompaniesController : ApiController
{
private MultiTierWebApiContext db = new MultiTierWebApiContext();
private static readonly Expression<Func<Company, CompanyDetailDTO>> AsCompanyDetailDTO =
x => new CompanyDetailDTO
{
Name = x.Name,
Email = x.Email,
isCustomer = x.isCustomer,
isSupplier = x.isSupplier,
Id = x.Id
};
private static readonly Expression<Func<Company, CompanyMediumListDTO>> AsCompanyMediumListDTO =
x => new CompanyMediumListDTO
{
Name = x.Name,
Email = x.Email,
Id = x.Id
};
private static readonly Expression<Func<Company, CompanyLightListDTO>> AsCompanyLightListDTO =
x => new CompanyLightListDTO
{
Name = x.Name,
Id = x.Id
};
// GET: api/Companies/LightList
[Route("api/Companies/LightList")] **It works, but is this a correct way to do it?**
[ResponseType(typeof(CompanyLightListDTO))]
public IQueryable<CompanyLightListDTO>GetCompaniesLightList()
{
return db.Companies.Select(AsCompanyLightListDTO); // default
}
// GET: api/Companies/MediumList
[Route("api/Companies/MediumList")]
[ResponseType(typeof(CompanyMediumListDTO))]
public IQueryable<CompanyMediumListDTO> GetCompaniesMediumList()
{
return db.Companies.Select(AsCompanyMediumListDTO); // default
}
// remaining code removed for simplicity
}
Thanks in advance for further help.
I would say you are on the right track with only providing the relevant information related to the particular DTO. Don't provide more data than necessary.
If you look at the following walk-through you will see how they follow a similar pattern to what you have in your example.
Create a REST API with Attribute Routing in ASP.NET Web API 2
Quoting for reference:
Instead, I want this request to return a subset of the fields. Also, I
want it to return the author's name, rather than the author ID. To
accomplish this, we'll modify the controller methods to return a data
transfer object (DTO) instead of the EF model. A DTO is an object that
is designed only to carry data.
// Typed lambda expression for Select() method.
private static readonly Expression<Func<Book, BookDto>> AsBookDto =
x => new BookDto
{
Title = x.Title,
Author = x.Author.Name,
Genre = x.Genre
};
// GET api/Books
public IQueryable<BookDto> GetBooks()
{
return db.Books.Include(b => b.Author).Select(AsBookDto);
}
My advice would be to separate the transformation/projection functionality out of the controller (SoC) into their own service(s) (SRP) and inject them (DI) into the ApiController. It will keep your Controllers light.
I'm trying out the specFlow assist and not sure how would one create class property from table.
Imagine I have this class:
public class Tracking
{
public string Category { get; set; }
}
public class ODARequest
{
public string Title { get; set; }
public string Name { get; set; }
public Tracking Tracking { get; set; }
}
My Given scenario is next:
Scenario: Successfully create an account
Given I have entered the following data into the ODA form:
| Field | Value |
| Title | Mr |
| Name | Andy |
| Tracking Category | MDA |
public void GivenIHaveEnteredTheFollowingDataIntoTheODAForm(Table table)
{
var request = table.CreateInstance<ODARequest>();
}
The Tracking property will not be populated. Anyone know how to describe Tracking.Category in the table for this situation?
I haven't been able to find a way of getting specflow to map "CreateInstance" to non-standard data types properties.
However, in this case you could at least use a StepArgumentTransformation as follows:
[Given(#"I have entered the following data into the ODA form:")]
public void GivenIHaveEnteredTheFollowingDataIntoTheODAForm(ODARequest request)
{
Assert.IsNotNull(request.Tracking);
}
[StepArgumentTransformation(#".*")]
public ODARequest StringToTracking(Table input)
{
return new ODARequest() {
Title = input.Rows.Single(row => row["Title"])["value"],
Name = input.Rows.Single(row => row["Name"])["value"],
Tracking = new Tracking()
{ Category = input.Rows.Single(row => row["Field"] == "Tracking Category")["Value"] }
};
}
With a little work you could tidy the stepargumenttransformation up to accept each parameter as optional (rather than having "single()" throw if it is omitted).
I feel like there really ought to be a better way to do this, more like your original suggested code.
Hope this is helpful.
I've been hitting this problem and been thinking how to do it with a single step.
Scenario: Successfully create an account
Given I have entered the following data into the ODA form:
|Title | Name | Category|
| Mr | Andy | MDA |
public void GivenIHaveEnteredTheFollowingDataIntoTheODAForm(Table table)
{
var request = table.CreateInstance<ODARequest>();
request.Tracking = table.CreateInstance<Tracking>();
}
How it works:
You may call "CreateInstance" for each complex property you have so specflow will create you an instance. So you can have a single table with properties from different types.
By doing so you won't need a different step and the need of sharing data between the steps.
The drawback is that you may end up with a huge table if your class has a lot of properties with different types.
Note: As #Alex M commented it there is a risk when the classes are having a property with same name. What will happen actually is that both instances will get the same value due to the property name match on both classes.
Another possibility without modifying the specflow assist itself is to separate the subclass properties into separate Given.
Can be as per below example:
Scenario: Successfully create an account
Given I have entered the following data into the ODA form:
| Field | Value |
| Title | Mr |
| Name | Andy |
And the tracking info as:
| Tracking Category | MDA |
then my step definitions would be as:
[Given(#"I have entered the following data into the ODA form:")]
public void GivenIHaveEnteredTheFollowingDataIntoTheODAForm(Table table)
{
var request = table.CreateInstance<ODARequest>();
ScenarioContext.Current.Set(request, "request");
}
[Given(#"the tracking info as:")]
public void GivenTheTrackingInfoAs(Table table)
{
var request = ScenarioContext.Current.Get<ODARequest>("request");
request.TrackingFields = table.CreateInstance<Tracking>();
}
Otherwise the possibility is to contribute to specflow assist development.
I have a dropdown datatype which has all the child nodes of a parent node. I can create this list manually. But the problem is, the child nodes will be created/deleted on the fly, which means I need to edit/remove the dropdown values manually each time.
Is there a way to add/remove items from dropdown list whenever my parent node is published??
Please let me know.
Assuming you are using the latest version of Umbraco, you can register an event on document publish which will fire for every single event publish. In the event handler code you can then selectively fire for only the node you are concerned with.
http://our.umbraco.org/documentation/Reference/Events/application-startup
Something like the following should do it
using Umbraco.Core;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic;
using umbraco.cms.businesslogic.web;
namespace Umbraco.Extensions.EventHandlers
{
public class RegisterEvents : ApplicationEventHandler
{
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
Document.BeforePublish += Document_BeforePublish;
}
private void Document_BeforePublish(Document sender, PublishEventArgs e)
{
//Do what you need to do. In this case logging to the Umbraco log
Log.Add(LogTypes.Debug, sender.Id, "the document " + sender.Text + " is about to be published");
if (sender.Id == YourIDAsAConstantOrConfigurableValue)
{
//Do your list building here
}
//cancel the publishing if you want.
e.Cancel = true;
}
}
}
You can trigger selectively for your specific parent node based on either ID or based on document type alias
Hope that helps
I have created a custom feature for sharepoint 2007 using visual studio 2010. When I activate the feature it of course fires on all document libraries in the site collection. can someone give me an example of how to make the feature fire on a specific document library/list instance.
First you'll have to add an EventReceiver to your feature and then in your Feature's xml add a ReceiverClass, like this:
<Feature Id="f68efad8-ea0a-42a2-9994-db3b74aa67f8"
Title="My features title"
Description="Blah blah blah"
Version="12.0.0.0"
Hidden="FALSE"
Scope="Web"
DefaultResourceFile="core"
ReceiverAssembly="MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c4f34f956cd0552b"
ReceiverClass="MyProject.FeatureCode.EventHandler" <!-- This is where you set the EventReceiver -->
xmlns="http://schemas.microsoft.com/sharepoint/">
EventHandler being the EventReceiver when you're feature is activated.
My example
First of, my eventreceiver:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
var assembly = typeof(PermissionHandler).Assembly.ToString();
var classList = typeof(PermissionHandler).FullName;
var web = SPContext.Current.Web;
web.AllowUnsafeUpdates = true;
try
{
var list = web.Lists["MyList"];
list.EventReceivers.Add(SPEventReceiverType.ItemAdded, assembly, classList);
list.EventReceivers.Add(SPEventReceiverType.ItemUpdated, assembly, classList);
}
catch (Exception ex)
{
EventLogger.LogError("Sample feature failed to run.", this, ex);
}
}
In the above example I want to add some permissions to the elements in MyList.
As you can see I make 2 variables which is the typeof(PermissionHandler), which is a public class I've created to do the job.
I have added 5 items to the list before activating this feature, so I want the already existing items to also get the permissions I'm setting for the new items. This is how I do it:
private void updateItemPermissions(SPItemEventProperties properties)
{
DisableEventFiring();
SPListItem listItem = properties.ListItem;
SPSecurity.RunWithElevatedPrivileges(() =>
{
SPSite site = new SPSite(listItem.ParentList.ParentWeb.Site.ID);
SPWeb web = site.OpenWeb(listItem.ParentList.ParentWeb.ID);
SPList list = web.Lists[listItem.ParentList.ID];
SPListItem item = list.Items.GetItemById(properties.ListItem.ID);
item.BreakRoleInheritance(true);
if (item.RoleAssignments.Count > 0)
{
for (var i = item.RoleAssignments.Count - 1; i >= 0; i--)
item.RoleAssignments.Remove(i);
}
var group = item.Web.Site.RootWeb.Groups["Visitors"];
AddPermissions(item, web, SPRoleType.Reader, group);
});
EnableEventFiring();
}
private static void AddPermissions(SPListItem curItem, SPWeb web, SPRoleType roleType, SPPrincipal principal)
{
SPRoleDefinition roleDefinition = web.RoleDefinitions.GetByType(roleType);
SPRoleAssignment roleAssignment = new SPRoleAssignment(principal);
roleAssignment.RoleDefinitionBindings.Add(roleDefinition);
curItem.RoleAssignments.Add(roleAssignment);
curItem.Update();
}
I hope this helped you :)