Prevent content with child nodes from being deleted in umbraco - umbraco

I would like to prevent content nodes from being trashed if they have any children. I setup an event handler like so:
public class KeepSafeEvents : ApplicationBase
{
public KeepSafeEvents()
{
Document.BeforeMoveToTrash += new Document.MoveToTrashEventHandler(Document_BeforeMoveToTrash);
}
void Document_BeforeMoveToTrash(Document sender, umbraco.cms.businesslogic.MoveToTrashEventArgs e)
{
if (sender.HasChildren)
{
e.Cancel = true;
}
}
}
However, this doesn't seem to work. I assume it is because the delete process moves the child nodes to trash first before dealing with the parent node (which then has no children). Is there another possible solution? Or am I making a simple mistake above?

This code works perfectly for me. Are you sure that you've copied the resulting .dll file to Umbraco's /bin folder?
I just wrote it a little shorter than you did, like below, but the functionality should be exactly the same.
I do notice that the document with childnode seems to get deleted (it disappears from the tree), but when you reload the tree, the node is still there.
public class KeepSafeEvents : ApplicationBase
{
public KeepSafeEvents()
{
Document.BeforeMoveToTrash += Document_BeforeMoveToTrash;
}
void Document_BeforeMoveToTrash(Document sender, MoveToTrashEventArgs e)
{
if (sender.HasChildren)
e.Cancel = true;
}
}

Related

Xtext CustomScopeProvider Problems with adding candidates

I am working on an xtext Project where I have to customize the Scope Provider. I need to add up some possible candidates for the scope. The first part (getServiceInputs()) works fine but for the second one (addAll(sub.GetSubRecipeParameters()) not. Debugging showed that they get removed from its original source (sub) and can therefore not be retrieved again. When simply commenting out the addAll line the SubRecipeParameters remain in sub. Really dont know how to solve that, tried already some work arounds. Anyone with an Idea?
public class AutomationServiceDslScopeProvider extends AbstractAutomationServiceDslScopeProvider {
#Override
public IScope getScope(EObject context, EReference reference) {
if (context instanceof ServiceInvocationParameter
&& reference == AutomationServiceDslPackage.Literals.LITERAL) {
ServiceInvocation serviceCall = (ServiceInvocation) invocationParameter.eContainer();
ServiceDefinition calledService = serviceCall.getService();
List<ServiceParameterDefinition> candidates= calledService.getServiceInputs();
final EObject rootContainer = EcoreUtil.getRootContainer(context);
List<SubRecipeDefinition> subs = EcoreUtil2.getAllContentsOfType(rootContainer, SubRecipeDefinition.class);
for(SubRecipeDefinition sub:subs) {
for(RecipeStep step:sub.getRecipeSteps()) {
if(step.getName()==serviceCall.getName()) {
candidates.addAll(sub.getSubRecipeParameters());
}
}
}
return Scopes.scopeFor(candidates);
Thanks for any help!!
This is normal EMF behaviour if you move elements from one EList to another one. The solution is to create a new list e.g. new ArrayList<>() and also add the inputs there
List<ServiceParameterDefinition> candidates = new ArrayList<>();
candidates.addAll(calledService.getServiceInputs());

Is it possible to hide Vaadin Version

Is there any way to hide the version of vaadin version (i.e v=7.6.2) in page source? Also is it possible to change the default directory "VAADIN" to any other directory or rename it?
I think it is impossible to get rid of VAADIN directory name because it is hardcoded in some framework classes on server and client side. For example: com.vaadin.server.BootstrapHandler, com.vaadin.server.VaadinServlet and com.vaadin.client.ui.ui.UIConnector
Technically speaking it is possible to hide Vaadin version. All you need is to register BootstrapListener at the start of Servlet session
public class ApplicationBootstrapListener implements BootstrapListener {
#Override
public void modifyBootstrapFragment(BootstrapFragmentResponse response) {
List<Node> nodes = response.getFragmentNodes();
for (Node node : nodes) {
if (node.toString()
.contains("js?v=")) {
String fakeVersion = node.attr("src")
.replace("7.5.8", "1.1.1");
node.attributes()
.put("src", fakeVersion);
}
}
}
#Override
public void modifyBootstrapPage(BootstrapPageResponse response) {
}
}
//somewhere in servletInitialized()
getService().addSessionInitListener(event -> event.getSession()
.addBootstrapListener(
new ApplicationBootstrapListener()));
After this step application should stop working though. That's because Vaadin won't be able to find vaadinBootstrap.js since you has changed its name. You may need to copy the content of this JavaScript, put it somewhere in the public folder and rename it to whatever fake name you want (in my case it would be vaadinBootstrap.js?v=1.1.1.
As for the second question, I also think it is impossible, at least without a help of reverse engineering.
Building on Kuki's answer, this worked for me on Vaadin 8.9.4, no need to copy any js-file.
#Override
public void modifyBootstrapFragment(BootstrapFragmentResponse bootstrapFragmentResponse) {
final List<Node> nodes = bootstrapFragmentResponse.getFragmentNodes();
final String oldVersion = "8.9.4";
final String fakeVersion = "x.y.z";
for (Node node : nodes) {
/* replacing the version in src-attributes */
if (node.attr("src").contains(oldVersion)) {
node.attributes().put("src", node.attr("src").replace(oldVersion, fakeVersion));
}
/* replacing the version in the child-DataNodes */
for (Node child : node.childNodes()) {
if (child instanceof DataNode) {
final DataNode dataNode = ((DataNode) child);
if (dataNode.getWholeData().contains(oldVersion)) {
dataNode.setWholeData(dataNode.getWholeData().replace(oldVersion, fakeVersion));
}
}
}
}
}

Umbraco : Refresh dropdown datatype items automatically on parent node publish

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

java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor#

I've read several related posts and even posted and answer here but it seems like I was not able to solve the problem.
I have 3 Activities:
Act1 (main)
Act2
Act3
When going back and forth Act1->Act2 and Act2->Act1 I get no issues
When going Act2->Act3 I get no issues
When going Act3->Act2 I get occasional crashes with the following error: java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor#.... This is a ListView cursor.
What I tried:
1. Adding stopManagingCursor(currentCursor);to the onPause() of Act2 so I stop managing the cursor when leaving Act2 to Act3
protected void onPause()
{
Log.i(getClass().getName() + ".onPause", "Hi!");
super.onPause();
saveState();
//Make sure you get rid of the cursor when leaving to another Activity
//Prevents: ...Unable to resume activity... trying to requery an already closed cursor
Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor();
stopManagingCursor(currentCursor);
}
When returning back from Act3 to Act2 I do the following:
private void populateCompetitorsListView()
{
ListAdapter currentListAdapter = getListAdapter();
Cursor currentCursor = null;
Cursor tournamentStocksCursor = null;
if(currentListAdapter != null)
{
currentCursor = ((SimpleCursorAdapter)currentListAdapter).getCursor();
if(currentCursor != null)
{
//might be redundant, not sure
stopManagingCursor(currentCursor);
// Get all of the stocks from the database and create the item list
tournamentStocksCursor = mDbHelper.retrieveTrounamentStocks(mTournamentRowId);
((SimpleCursorAdapter)currentListAdapter).changeCursor(tournamentStocksCursor);
}
else
{
tournamentStocksCursor = mDbHelper.retrieveTrounamentStocks(mTournamentRowId);
}
}
else
{
tournamentStocksCursor = mDbHelper.retrieveTrounamentStocks(mTournamentRowId);
}
startManagingCursor(tournamentStocksCursor);
//Create an array to specify the fields we want to display in the list (only name)
String[] from = new String[] {StournamentConstants.TblStocks.COLUMN_NAME, StournamentConstants.TblTournamentsStocks.COLUMN_SCORE};
// and an array of the fields we want to bind those fields to (in this case just name)
int[] to = new int[]{R.id.competitor_name, R.id.competitor_score};
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter tournamentStocks = new SimpleCursorAdapter(this, R.layout.competitor_row, tournamentStocksCursor, from, to);
//tournamentStocks.convertToString(tournamentStocksCursor);
setListAdapter(tournamentStocks);
}
So I make sure I invalidate the cursor and use a different one. I found out that when I go Act3->Act2 the system will sometimes use the same cursor for the List View and sometimes it will have a different one.
This is hard to debug and I was never able to catch a crashing system while debugging. I suspect this has to do with the time it takes to debug (long) and the time it takes to run the app (much shorter, no pause due to breakpoints).
In Act2 I use the following Intent and expect no result:
protected void onListItemClick(ListView l, View v, int position, long id)
{
super.onListItemClick(l, v, position, id);
Intent intent = new Intent(this, ActivityCompetitorDetails.class);
intent.putExtra(StournamentConstants.App.competitorId, id);
intent.putExtra(StournamentConstants.App.tournamentId, mTournamentRowId);
startActivity(intent);
}
Moving Act1->Act2 Act2->Act1 never gives me trouble. There I use startActivityForResult(intent, ACTIVITY_EDIT); and I am not sure - could this be the source of my trouble?
I would be grateful if anyone could shed some light on this subject. I am interested in learning some more about this subject.
Thanks,D.
I call this a 2 dimensional problem: two things were responsible for this crash:
1. I used startManagingCursor(mItemCursor); where I shouldn't have.
2. I forgot to initCursorAdapter() (for autocomplete) on onResume()
//#SuppressWarnings("deprecation")
private void initCursorAdapter()
{
mItemCursor = mDbHelper.getCompetitorsCursor("");
startManagingCursor(mItemCursor); //<= this is bad!
mCursorAdapter = new CompetitorAdapter(getApplicationContext(), mItemCursor);
initItemFilter();
}
Now it seems to work fine. I hope so...
Put this it may work for you:
#Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
orderCursor.requery();
}
This also works
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
startManagingCursor(Cursor);
}

In EF4, Is there a way to have unmapped properties make it across the wire?

I have a custom field that I've added to one of my EF entities in a shared.cs file like so:
public partial class Content
{
public int Test = 5;
}
On the client side, the OnCreated handler for that same class looks like this:
partial void OnCreated()
{
this.Test = 42;
}
I've added an event handler to the SavingChanges event for the context on the server like this:
partial void OnContextCreated()
{
this.SavingChanges += (sender, e) =>
{
foreach (object o in GetChangedEntities())
{
if (o is Content)
{
// Break to see what the value of Test is;
}
}
}
}
When I break at the comment (which is not really a comment my code :), the value of Test is always 5. In fact, I can't seem to set it to 42 anywhere on the client and have that value make it to the server.
I have set breakpoints all over the place, and the value is definitely being set to 42 on the client-side. Is there something that I'm doing wrong, or is this behavior just not supported? Incidentally, I've also tried this as a property instead of a field--just in case.
I needed to mark my property/field as a [DataMember] like this:
public partial class Content
{
[DataMember]
public int Test = 5;
}
and then move it out of the shared.cs file to a CustomProperties.cs (or similar) file in the server project to avoid multiple delcarations. Now it crosses the wire just fine.

Resources