MVC 5 Save Drafts While Ignoring Missing Required Fields - asp.net-mvc-5

I have searched for current solutions, but can't find a set of guidelines or examples as to how to achieve the following:
The original requirements involved models with required fields, so we included annotations to those fields. As usual, there is a last-minute change and we are being asked to allow the users to save drafts. These drafts must allow the user to save the forms without any of the required fields.
I would like to know what the best practices for this problem are.
Solutions I am considering, but I accept they might be a hack (and that's why I am asking the experts)
If the user clicks "Save as Draft" I can capture the fields that have information in another ActionResult and run basic validation on those fields. Since there is a chance that required fields are missing, I am thinking in storing the captured info in a temporal model (without any required annotations). If the user decides to edit such form, I can populate fields in the view with the temp. model until the user clicks on "Submit"
Another option is to remove all required annotations and run client-side validations... but am wondering on the amount of work required to do so.
Any thoughts are very much appreciated.

Just have 2 save methods. 1 which is called from the autosave and 1 that is used to submit the process. In the autosave method do not check if(ModelState.IsValid).
Whether you choose to save the incomplete objects to the same table or a different table is your choice. In a relational world I would likely use a separate table, in a non-relational world I would use a singular object collection.
This will allow you to keep the same set of original models. There is a very high cost to duplicating your models, there are certainly times that warrants pass by value/copy but make sure the cost of mapping is there. In this situtation I do not believe there is value in mapping, except perhaps at the persistence level if you need to map to a different object because of an ORM's constraints.
There is deep value in these partial forms. Recording this on the server will allow you to apply analytics to learn why your users abandon your processes. It also gives you the ability to follow up on users who leave incomplete forms such as sending a reminder (nag) email.

You don't want to save anything to your database until it is complete. Having a duplicate table where everything is nullable is cludgy as hell. Before HTML5, the typical path was to save the information to the session, which you could then pull from to refill the fields, but that's requires having a session with a relatively high expiry to be useful.
Thankfully, HTML5 has local storage, which is really the best way to handle this now. You just watch for onchange events on your fields and then insert that value into local storage. If the user submits the form successfully, you destroy the local storage values. Otherwise, you attempt to read those values from local storage when the page loads and refill the fields.
See: http://diveintohtml5.info/storage.html
There's pretty broad support, so unless you need to worry about IE6 or IE7, you won't have any issues.

Another option (depending on your data obviously) would be to comply with the database but not the model. By this I mean ignore Model.isValid and disable Javascript validation on the front end but then satisfy the database table. In a form, you mostly have:
textboxes - default to "" or " "
checkboxes - easy true/false default
radio buttons - one is probably already selected
dates - default to DateTime.MinValue (or DateTimeUTC)
enums - default to 0 (usually for 'unspecified')
Hopefully you are also saving a flag designating that it is in Draft state so that you know you need to interpret the 'null codes' you have set when it comes to displaying the semi-populated form again.

Related

Adding and Removing Fields Programmatically on Forms

Sorry this isn't a specific coding question, it is more of a design concept.
What is the usage case for programmatically adding and removing fields to Notes Forms e.g. NotesDocument.RemoveItem(), ie why would you add and remove fields in the background?
For many years I have designed my forms with the fields layed out on the form which are required and then hide and show as required.
By adding dynamically you can't position them and frustratingly removing them or deleting they still appear the Database Fields in Domino Designer, getting rid of them is a bit a a black art, but that's another story.
I must be missing a trick or a basic design concept. Any thoughts on best practice would be appreciated.
Many thanks.
Yes, you are missing the difference between "Fields" and "Items". A field is a design element that you can place anywhere on your form. You define how it looks, what content it contains, what datatype it is, etc.
When creating a document with the form the value of the FIELD is stored in an ITEM in the resulting NotesDocument.
This item is totally decoupled from the field that created it. If you were to change the field in the form from text to number or move it around or make a names- field of it, the item in the existing documents would never change unless you open the documents and save them in frontend or use any LotusScript or Formula Code to recalculate the document in backend.
Very often items are added programmatically to documents to fulfill different purposes: Calculate values to be displayed in views, calculate values that are import for the workflow but not for the user, etc.
Complex applications often consist of a lot more items than there are fields in the several forms.
Back to your question: Removing an item from a document simply removes the value that was created by the field in the form. When reopening the document, the item will be repopulated, either by default value or whatever....
Usually you would use this to remove items that you no longer need (and probably already removed from the form).
As soon as you removed all references to a field / item everywhere in design and documents, you can finally get rid of it completely by compacting the database.
An item is distinct from a field in Notes. The form is purely a UI concept, the item is what the data is stored in.
Manipulating data in the backend can be used for a number of reasons. One such use case is the setting of a flag when a date on the form has expired.
Say you want a view showing all documents that have expired. Your rules dictate that documents are considered as "Expired" after 7 days. You could create a view with a formula that shows all document whose date is 7 days older than today:
SELECT Date < #Adjust(#Today; 0; 0; -7; 0; 0; 0);
This view will ALWAYS be out of date and will constantly be updated by the server as it re-evaluates #Today.
Now, a better way would be to create an agent that runs daily that sets an item on the document to indicate that it has expired e.g.
#SetField("Expired"; 1);
The view formula would then be
SELECT Expired = 1
The view would only need to update daily and you have a much faster view because of it.
RemoveItem is used to get rid of data no longer needed e.g. FaxNumber.
There are many use cases for RemoveItem. Here's one that comes up frequently.
You have a database and an agent that processes documents in that database. Every time it runs, the agent replaces the value of a bunch of items. There are a variety of error conditions that can cause it to abort processing a document early, but you're a smart programmer and you've accounted for that with on error traps. When you hit one, you log an error message, save your document, and then either abort your agent or go on to processing the next document.
But at this point, some of the items that the agent normally updates have values saved from this run, and some of them have values saved from a previous run. This might be bad. This might be confusing for someone who is looking at the item values and trying to figure out what's going on. This might even cause validation errors on the form.
So how do you avoid this? At the very beginning of your agent, you call a cleanup sub that finds and removes all the items that the agent is going to update. Now you have a clean slate, and if your agent hits that error condition, it can save whatever it can save without any concern about whether it is leaving things in an inconsistent state. Of course, in cases where you are doing this to avoid validation errors, your validation formulas will have to be smart enough to be checking #IsAvailable for dependent items, but that's a good practice anyhow.

Create domino view dynamically in XPages

I want to know if I can click a button in my XPage and dynamically create a Domino View and then show it in a panel control on the same page. The reason I want to do this is because I have a categorized view and I don't want to lose category data by using full text search. So I am thinking of creating a new view dynamically and pass my search parameters, like end date or start date, into the view selection formula.
Is it possible? Any other alternative solution is also welcome.
yes you can, but you don't want to. A Domino view takes space in the database and quite some time for its first use. So you end up with a lot of views taking space and the need to adjust database space after removal. Your response times will suck big time.
Categories as shown in Notes views are no web interaction pattern, so you might want to solve a problem that actually shouldn't exist.
The preferred method for Domino application is navigation / drill down over search. But you could do a FTSearch where you add your category to the search parameters and render your results in a repeat control instead of a view control. There you have more control over the look and feel.
Whether or not it's the best solution, the answer to the immediate question about creating a view on the fly is yes: the Database class has a couple "createView" methods to allow you to create a new view, either entirely from scratch or based on a named other view. From there, you can use the "setSelectionFormula" and "createColumn" methods in the created View to build what you want. You can't do EVERYTHING with those methods, but it may be enough.
One problem you'd likely run into is ACL access: you'll need Designer rights to the database, which a normal user most likely wouldn't have. If you use the sessionAsSigner object to fetch a signer version of the DB (say, "var signerDB = sessionAsSigner.getDatabase(database.getServer(), database.getFilePath())"), you can work from there. Off the top of my head, I don't remember if you will also have to up the "Maximum Internet access" setting on the last tab of the ACL to Designer as well, but you may.
I am assuming that you are referring to the problem that exists when you choose the documents based on the category. This is something that I find highly annoying and I wish that it was possible to turn this on and off. It makes sense for embedded views, but not for much else.
What I did to solve this was to include the category value in the next column. In this way that text could still be seen, even if it was a flat view.
Alternatively, you could also look into using a repeater control and create your own way of presenting the information. This would be used instead of a (Dynamic)ViewPanel control. You could then present the information any way you wanted as long as it is returned in the viewrow set.
Happy Programming!

Does CakePHP automatically deal with mass assignment vulnerabilities when saving modified data?

Edit:
After receiving more information from DCoder, the phrase I was searching for here is a "mass assignment vulnerability." That is to say, taking advantage of the convenience of methods that would save all valid fields to the database, regardless of their presence on the initial form (making them vulnerable to manipulated POST data containing more [possibly more critical] fields than the intended ones).
The two common responses are then appropriately named whitelisting and blacklisting; whitelisting fields intended for modification, or blacklisting fields that should not be modified.
My question then follows: does CakePHP automatically whitelist only those fields in the submitting form, or is it necessary for me (and other Cake fans) to be careful that we are whitelisting or blacklisting appropriately?
Original Question:
Cake offers a lot of great ways to generate forms and handle them nearly automatically. As I was thinking about security, I got to wondering: is Cake aware of what fields existed in a form submitted, or will it simply accept any valid field? Take the following senario if I'm not making sense (and someone is welcome to edit my question to be better worded if they can think of a better way to express it):
Let's say I allow my users to edit their profile. I create a form which has fields for username, e-mail, and password, under the action edit.
A clever user wants to come in and change their is_admin field from false to true, so they use an app like firebug to submit custom post data to the edit action, which includes the field is_admin set to true.
The question is, would Cake realize on it's own that is_admin was not in the original form, or do I need to be careful to explicitly specify the only fields which fields a given action can modify? Is there an easier way?
Thank you!
James
You have to load the SecurityComponent in your controller(s) and CakePHP will prevent form tampering for you, see http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#form-tampering-prevention
CakePHP has built in validation option available. The Form automatically generate the fields and do validation based on the validation criteria you have mentioned in the model. This validation will be called automatically before the Save method.
Also if you want to add some custom validation, you can add that in the model.
With your specific query you can remove the is_admin field from the edit form so that it won't be editable to the user. If you want to add more security and make sure that the is_admin field has false value you can edit its value in the controllers edit method.
In the edit method you can add the following code before calling the Save action.
$this->request->data['ModelName']['is_admin] = false;

creating many to many relationship between documents in different lotus notes databases

I am doing "traditional" lotus notes programming (same since R5) and need to implement linking between 2 document types (forms) residing in different databases.
Document of type (A) in database (A) can reference several documents of type (B) in database (B).
And document (B) should also display its relationships with document (A), as document (B) can be related to different documents (A).
We have Many to Many relationship.
At the moment it is implemented on one side only (one to many):
Form of Document (A) contains embedded view of special
"link" documents residing in database A. This link documents are created by lotusScript when user selects documents from database (B). When user clicks on an item in this embedded view, it opens document (B).
Client wants to be able to edit this relationship on any side, so that if he edits it in form (A), form (B) is updated.
Form (B) is supposed to have the same kind of embedded view or a list of associated documents of type (A)
What is the best way to implement it?
Client's infrastracture is Lotus Domino 8.5.2 + Lotus Notes 8.5.2, so theoretically, composite applications approach may be an option.
The reason why I ask this question is that as far as I understand there is no good way in Notes to embed a view from another database.
The requirement is that the database should be present on workspace to be displayed in some sort of dodgy list.
It would be great to be able to specify target database for embedded view by server and replicaID, but instead we have a weird list of random workspace databases.
The main problem is that Notes wasn't designed to handle relationships like that between databases (nor anything besides parent child relationships for that matter). So the solution will have to be a creative one.
A couple of (off-the wall, potentially awful) ideas come to mind. One is to store the references in the documents themselves, and update them whenever the document is saved. That could all be done in LotusScript, and would require searching through the other database's documents to update their references.
Upside is that the performance when reading the documents would be excellent. There'd be no issues while reading Database A if Database B was unavailable. It keeps data local to each database. The downsides include the likelihood of save conflicts and the danger that references could get out of sync if documents aren't "saved" but instead are updated via agents, etc.
Another thought is to use agents to manage the links on a scheduled basis. If you don't need real-time up-to-date references, you could run an agent that scans Database B and updates the references in Database A. With this method you could choose either to update the Database A documents themselves - or - as it sounds like you've already done, create a set of link documents that show up in an embedded view. The latter eliminates the save conflict problem.
One more idea is to hide any references when you open a document in Database A, but provide a button to "show" or "update" references. When you click that button, it fires off LotusScript to search Database B and build a list on the fly. This would probably work quickly with less than 10,000 documents. That function could update the link documents you store on the same database which feed the embedded view.
Hope this helps!
What is the best way to implement it?
As you mention creating a composite application may allow you to do this, but would be restricted to windows rather then design level in the form.
eg.
[Window A] --- trigger ---> [Window B]
If you are not familiar with this system I did a tutorial which explains the basics.
http://www-10.lotus.com/ldd/compappwiki.nsf/dx/ibm-my-first-wire
Although the tutorial calls back to the same database, it is easy enough to point to a different one.
Personally I'd do it through XPages. I personally find it much easier to implement then through classic style notes design/comp apps. It will also allow you to display design elements within the same screen area.
As you've already heard, Lotus Notes has no referential integrity constraints built-in, you have to do it yourself.
I wouldn't be relying on document links as they're geared around UNID's which can change if you cut and paste the same document, thus losing the link. Try this,
1/ Create an "ID" field on each document. You can populate it by using #Unique in a computed field to generate an ID, and save that to the documents in both databases. You can create an agent to do this in lotusScript (LS), or formula. (Consider using the evaluate statement if doing in LS)
2/ Create a lookup view in each database that lists the documents by the new ID (don't forget to set the "sort order" of the ID column.
3/ Using an action button that can be configured for both databases, you can create a LS function that will open the the opposing databases view and return the ID field. (NotesUIWorkspace.pickliststrings would be the simplest way to pick the documents, otherwise you could build a dialogbox. Store the list of results in a field called "linkedID" as multi-value list.
4/ There may be more info that you want to store like document title or author, so you'll need to then get a handle to those documents using getdocumentbykey and then interrogating the fields you'll need to display information on screen.
5/ You can then also add a new field on the target documents you're referring to, call it "referrerID", which is a list of documents that reference the current document. This will maintain the two-way relationship.
The field that stores links must be a multi-valued field, otherwise it gets quite cumbersome to loop through list of linked document ID's and manage them.
This approach uses a static key so you can copy databases around without losing the relationships between documents the user has invested time in producing. You can (and probably will) lose those relationships if you rely on document universal ID's (described well in the #documentUniqueID documentation), if you cut and paste the document, or copy the database somewhere else they become new documents despite copying the same fields, and will be assigned a new universal ID, any document links for the old document will be invalid.
If the information you're displaying from the other database changes, you'll need to be able to refresh that data regularly, so consider writing a scheduled agent that can do the look up and refresh the relevant fields.
If the user intends to un-link or change the relationships between documents, then you'll need to add functions that loop through the key fields and keep the lists consistent with what the user is doing. So, like I said, Lotus Notes' flat data structure requires you manage all integrity constraints yourself.
If you want to get a little fancy you can use embedded views as they do support references from another database on the same server. Some tips about handling it in LotusScript here. And use an additional view that categorises your data by the referring ID. Embedded views are ok, as long as the view they're based on is not too big, otherwise it may affect the performance of the form that it is embedded into.

Enable/disable editing of a form field from code

I'm not a Notes programmer, however, for my sins, have been working on some Notes features for an in-house project recently. I need to enable/disable editing of a field depending on circumstances. It seems to me to be a fairly standard feature, I need, but I can't find any information on how to do this anywhere.
In form setup (and other field's onchange) code, something like the following:
if some requirement = true then
textField.enable = true
else
textField.enable = false
end if
I've seen other places where there's a workaround of conditionally hiding paragraphs based on some code, having 2 paragraphs with opposite hiding conditions, one with an editable field, the other with a computed field. However, I don't know enough about Notes to see how this is implemented (I can see it done on other forms, but there seem to be some 'magic' steps within Notes which I either can't see or don't get).
[EDIT]
The reply from Kerr seems to be what I'm looking for, but I still can't find out where the InputEnabled property is located. Should have said in the initial question, I'm using Notes 7.0.3.
In fairness, it doesn't matter what the circumstances are for when to enable/disable the field, it's just some boolean condition that is set, in my case only on form loading so I don't even have to worry about this changing dynamically while the form is displayed.
I've got a few issues with Notes, my largest bugbear being that it's so tied so tightly to the Designer UI, which is utter shite. I can do this sort of thing programmatically in most GUI languages (C#, Java, Delphi, even VB), but I need to open property boxes in Notes and set them correctly.
This would be OK as an optional method, but forcing you to go this way means you can only work as well as the IDE lets you in this case, and the IDE here seems to actively work against you. You can't open multiple functions/scripts, you can't swap from one script to another without going back to the menus on the left, you can't easily search the codebase for occurrences of variables/fields (and believe me, this is a major failing for me because either Notes or the internal codebase in my case seems to make a lot of use of global variables!), you can only work with fields through the property boxes that get displayed, you can't edit code in Designer while debugging through the main Notes client.
While the Java side of the coding is better than LotusScript, it's still fairly crappy (why can't you debug INTO Java code?? Why do you need to re-import JAR files for each Java class, does each class have a different CLASSPATH???). Possibly this was improved in Notes 8, I hear it's based on Eclipse. Does anyone know whether this is true or not?
It would help to hear more specifics about the 'circumstances', but the most common way to handle this is to use a hide when formula on the field you want to enable/disable.
Technically you are not enabling or disabling the field, just hiding it, but usually that works just as well.
Since there are few events to work with in Notes, developers commonly use the document refresh as the 'event' to cause the field to hide or show.
Let's assume you have two fields called TriggerField and Subject. Say also you want to disable the Subject based on a value in the TriggerField. The easiest way to do so is to set the TriggerField as a Dialog List type and check the "Refresh fields on keyword change" option. This means when the value of the dialog list changes, the entire document will get refreshed.
Then in your hide when formula for the Subject field, you specify your criteria for when to show or hide that field. Anytime field values change, followed by a refresh of the document (i.e. form), that hide when formula will be re-evaluated.
There are other ways, depending on your circumstances, to solve this problem. If you want to let the user refresh the form themselves, put a button on the form that calls the #Command([ViewRefreshFields]) command. You can add any other formulas to that button before the refresh command if you want to make other changes to the form at the same time.
Another option is to make a certain field display-only. Then create a button that runs LotusScript to allow users to change that display-only field. In the script you can propmt the user for a value, set the display-only field, and then call for a document refresh.
In ND7 and up if you want to just disable the field for input, write an appropriate formula in the InputEnabled section of the field you want to disable.
So I have two fields one called Trigger, a checkbox with the value "On" and another Subject that is a text field. When Trigger is checked I want the value Subject to be enabled.
I simply put the following formula in the Input Enabled element of the field Subject:
Trigger = "On"
I also want this to be recalculated whenever the value of Trigger changes so I select the "Refresh fields on keyword change" option on the Trigger field.
If you're stuck in an older version you need to to hide paragraphs appropriately.

Resources