Stop validation error item from being published - validation

We are using Sitecore 7.2 and have implemented the 'Required' field validator for number of fields.
However, the user can still save or create an item with validation error.
I know that we can stop this validation errored items from being published using Work Flow.
We do not want to implement any workflow, therefore can someone please suggest how to stop validation errored item from being able to published?

You can create your own validation class like this (the one below only check for validation bar errors):
public void ValidateItem(object sender, EventArgs args)
{
ItemProcessingEventArgs theArgs = (ItemProcessingEventArgs) args;
Item currentItem = theArgs.Context.PublishHelper.GetSourceItem(theArgs.Context.ItemId);
if ((currentItem != null) && (currentItem.Paths.IsContentItem))
{
if (!IsItemValid(currentItem))
{
theArgs.Cancel = true;
}
}
}
private static bool IsItemValid(Item item)
{
item.Fields.ReadAll();
ValidatorCollection validators = ValidatorManager.GetFieldsValidators(
ValidatorsMode.ValidatorBar, item.Fields.Select(f => new FieldDescriptor(item, f.Name)), item.Database);
var options = new ValidatorOptions(true);
ValidatorManager.Validate(validators, options);
foreach (BaseValidator validator in validators)
{
if (validator.Result != ValidatorResult.Valid)
{
return false;
}
}
return true;
}
and add event handler to publish:itemProcessing event:
<event name="publish:itemProcessing" help="Receives an argument of type ItemProcessingEventArgs (namespace: Sitecore.Publishing.Pipelines.PublishItem)">
<handler type="My.Assembly.Namespace.ValidateBeforePublish, My.Assembly" method="ValidateItem"/>
</event>

You could set the parameters field on the validation to "Result=FatalError" to stop the user from saving an item before the issue is resolved. This way the user has to fix the issue before they are allowed to save.

Related

Blazor: BitDatePicker show validation message. How to modify the message?

<BitDatePicker #bind-Value="Model.Date"
AllowTextInput="true"
DateFormat="yyyy/M/d"
GoToToday="امروز" Placeholder="تاریخ را وارد کنید"
Culture="PersianCultureHelper.GetFaIrCultureByFarsiNames()"
Style="width:150px; display:inline-block;">
</BitDatePicker>
(https://i.stack.imgur.com/B45TB.png)
how to change(modify) the default validation message of this component?
I create a class that inherits from "ValidationAttribute" to override the error message by custom regex validation. but two messages show when the input is not valid.
I don't want to use "Require" attribute. it should show the message when the input is not valid.
Not that simple. It's hard coded into the component.
However there is a way.
BitDatePicker is a component that emulates a standard InputBase type component, though it doesn't implement InputBase. The validation message is generated in `TryParseValueFromString' which looks like this:
protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out DateTimeOffset? result, [NotNullWhen(false)] out string? validationErrorMessage)
{
if (value.HasNoValue())
{
result = null;
validationErrorMessage = null;
return true;
}
if (DateTime.TryParseExact(value, DateFormat ?? Culture.DateTimeFormat.ShortDatePattern, Culture, DateTimeStyles.None, out DateTime parsedValue))
{
result = new DateTimeOffset(parsedValue, DateTimeOffset.Now.Offset);
validationErrorMessage = null;
return true;
}
result = default;
validationErrorMessage = $"The {DisplayName ?? FieldIdentifier.FieldName} field is not valid.";
return false;
}
So we can create a child component and override TryParseValueFromString. Note that you have to "capture" the content generated in the parent and re-gurgitate it in the child.
MyBitDatePicker
#using System.Diagnostics.CodeAnalysis;
#inherits BitDatePicker
#this.ParentContent
#code {
public RenderFragment ParentContent;
public MyBitDatePicker()
{
ParentContent = (builder) => base.BuildRenderTree(builder);
}
/// <inheritdoc />
protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out DateTimeOffset? result, [NotNullWhen(false)] out string? validationErrorMessage)
{
var isValid = base.TryParseValueFromString(value, out result, out validationErrorMessage);
//Custom message defined here
validationErrorMessage = $"The {DisplayName ?? FieldIdentifier.FieldName} field ain't right!";
return false;
}
}
You could prevent the problem in the first place by disabling AllowTextInput. The user then can't select an invalid date.

UI gets stuck while loading lot of data from realm

I am trying to show 10,000 contacts on listview in xamarin forms using realm. But whenever user traverse to contact listing screen
it gets freezed and loads after a while.
Moreover , i have provided an option to search from list as well and that too gets stuck as search if performing on UI thread.
Following is the code to load data from realm
public override async Task Initialize(Object data )
{
private Realm _realmInstance = getRealm();
if (contactList != null)
{
contactList.Clear();
}
contactList = _realmInstance.All<Contact>().OrderByDescending(d => d.contactId).ToList();
// here the binding happens with realm data
contacts = new ObservableCollectionFast<Contact>(contactList);
}
public ObservableCollectionFast<Contact> contacts
{
get { return items; }
set
{
items = value;
OnPropertyChanged("contacts");
}
}
as it was taking time in loading i thought to fetch realm data in background and bind it on UI thread as follows
but that is throwing error
realm accessed from incorrect thread
await Task.Run(() => {
contactList = _realmInstance.All<Contact>().OrderByDescending(d => d.contactId).ToList();
});
if (contactList.Count() > 0)
{
ContactListView = true;
AddContactMsg = false;
}
else
{
AddContactMsg = true;
}
Device.BeginInvokeOnMainThread(() =>
{
contacts = new ObservableCollectionFast<Contact>(contactList);
});
i wanted to try limiting the results by using TAKE function of LINQ but unfortunately its not supported by realm yet. not sure how i can smoothly load records from realm to listview.
EDIT
as per the SushiHangover i have changed things from IList to IQueryable
public IQueryable<Contact> contacts
{
get { return items; }
set
{
items = value;
OnPropertyChanged("contacts");
}
}
public override async Task Initialize(Object data )
{
_realmInstance = getRealm();
contacts = dbContactList= _realmInstance.All<Contact>();
}
so far search is working pretty smoothly but IQueryable change leads to another issue. on repeatedly performing following steps results in app crash
tap on list item
detail page gets open then press back
scroll down to few records
perform step 1 and repeat
this results into stackoverflow error
04-19 06:05:13.980 F/art ( 3943): art/runtime/runtime.cc:289]
Pending exception java.lang.StackOverflowError thrown by 'void
md5b60ffeb829f638581ab2bb9b1a7f4f3f.CellAdapter.n_onItemClick(android.widget.AdapterView,
android.view.View, int, long):-2' 04-19 06:05:13.980 F/art (
3943): art/runtime/runtime.cc:289] java.lang.StackOverflowError: stack
size 8MB
Link to entire log file
code to fire item click command is
public ICommand OnContactSelectCommand => new Command<Contact>(OnContactSelect);
following code will open ups a detail page
private async void OnContactSelect(Contact contact)
{
if (contact != null)
{
await NavigationService.NavigateToAsync<ContactDetailViewModel>(contact.mContactId);
}
}
Note:
when i replace IQueryable with List i do not face any error
somehow my issue is related to realm github thread where user is getting exception on listView.SelectedItem = null while using IQueryable
here is my code of list view item tap
private static void ListViewOnItemTapped(object sender, ItemTappedEventArgs e)
{
var listView = sender as ListView;
if (listView != null && listView.IsEnabled && !listView.IsRefreshing)
{
// have commented this line because it was crashing the app
//listView.SelectedItem = null;
var command = GetItemTappedCommand(listView);
if (command != null && command.CanExecute(e.Item))
{
command.Execute(e.Item);
}
}
}

How to handle changes in a form with a model-update using Wicket and AJAX

I have a form with many input-fields and need to handle a change to any of those input-fields; so I add a AjaxEventBehavior to the form, like:
Form<MyX> myForm = new Form<>("X", getModel());
myForm.add(new AjaxEventBehavior("onchange") {
#Override
protected void onEvent(AjaxRequestTarget target) {
handleFormChange(...);
}
});
The method handleFormChange gets called everytime I change some content in the input-fields of the form. But the model is not getting updated with the new value of the changed input-field of the form.
How can I get thoose model-updates? I tried AjaxFormComponentUpdatingBehavior. It updates the model, but I cannot use it for forms, just for FormComponents.
Does anybody has an ideas how to handle that? TIA!
With AjaxFormSubmitBehavior you can submit the whole form on each change.
First for on change use the dedicated OnChangeAjaxBehavior.
Then you can use the Iterator of the form to get all children and add then add the OnChangeAjaxBehavior to all FormComponents which will call your handleFormChange() on every change like this:
for (Iterator it = form.iterator(); it.hasNext();) {
Object o = it.next();
if (o instanceof FormComponent) {
((FormComponent) o).add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget target) {
handleFormChange(...);
}
});
}
}

Accessing User in Entity partial class via OnContextCreated()?

All of my tables have common audit fields: modifiedBy,modifiedDateTime, etc.
I would like to have these automatically set, and can set most of them with the following code:
partial class myEntities
{
partial void OnContextCreated()
{
this.SavingChanges += new EventHandler(Entities_SavingChanges);
}
private void Entities_SavingChanges(object sender, EventArgs e)
{
IEnumerable<ObjectStateEntry> objectStateEntries =
from ose
in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
where ose.Entity != null
select ose;
var auditDate = DateTime.Now;
var auditUser = System.Web.HttpContext.Current.User.Identity.Name;//I wish
foreach (ObjectStateEntry entry in objectStateEntries)
{
ReadOnlyCollection<FieldMetadata> fieldsMetaData = entry.CurrentValues.DataRecordInfo.FieldMetadata;
FieldMetadata modifiedField = fieldsMetaData.Where(f => f.FieldType.Name == "ModifiedBy").FirstOrDefault();
if (modifiedField.FieldType != null)
{
string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;
if (fieldTypeName == PrimitiveTypeKind.String.ToString())
{
entry.CurrentValues.SetString(modifiedField.Ordinal, auditUser);
}
}
}
}
}
The problem is that there doesn't appear to be any way to get access to the current user. The app is intranet only, using Windows auth.
Is there a way to either pass in a parameter, or get access to the HttpContext (which doesn't seem like it would be a good idea, but I'm stuck)? Is there a way to populate the EventArgs with information?
Check out the section where the poster has overridden the SaveChanges method (6th code box down on the page). This way you can pass in the UserID and perform your audit and not have to use an event handler.

Silverlight ValidationSummary not handling ValidationException

I have a dataform and a datagrid in the dataform. this datagrid is bound to an ObservableCollection. I have written a CustomValidator that throws ValidationException when the count in the observable collection is 0. ValidationSummary control doesn't handle this exception, instead the application becomes unstable and calls Application Unhandled Exception. I am not using RIA services. Below is my code
public class UserCompanyProgram : INotifyPropertyChanged
{
public void ToWebServiceProgram()
{
lstUserProgram.CollectionChanged += (sender, e) =>
{
//Validator.ValidateProperty(lstUserProgram,
// new ValidationContext(this, null, null) { MemberName = "lstUserProgram" });
lstUserProgram = _lstUserProgram;
UserProgramChanged();
};
}
private ObservableCollection<Pricing.Model.UserProgram> _lstUserProgram = new ObservableCollection<UserProgram>();
[CustomValidation(typeof(ModelValidator), "ValidateUserProgramCollection")]
[Display(Name = "New Programs", Description = "Add program")]
public ObservableCollection<UserProgram> lstUserProgram
{
get { return _lstUserProgram; }
set
{
Validator.ValidateProperty(lstUserProgram,
new ValidationContext(this, null, null) { MemberName = "lstUserProgram" });
this._lstUserProgram = value;
NotifyPropertyChanged("lstUserProgram");
}
}
}
dgSelectedPrograms.SetBinding(DataGrid.ItemsSourceProperty, new Binding("lstUserProgram") { ValidatesOnNotifyDataErrors=true, ValidatesOnExceptions=true });
How do I make the ValidationSummary handle the exception?
I had a similar issue in my project where I was forcing the validation on the keyup event of the textbox. I was setting the textbox bound property to the text from the textbox, on the keyup event, so I could validate as they typed. Silverlight does not like this. It was throwing an unhandled exception. So once I removed the validation from the keyup event, it worked as it should. The property does not get updated until the user selects another control on the screen, but if I want to take advantage of the Silverlight validation, that's what needs to be done.
I have not worked with validating a collection such as what you're doing, but maybe in cases like that you need to use the IDataErrorInfo implementation. An exception doesn't get thrown in that case, so that is probably the way to go.

Resources