In Kentico, is there a way to know the date the content was published for the first time? In the view_cms_tree_joined view there are fields called DocumentLastPublished and DocumentCreatedWhen but the latter is populated when the user save the content initially even if it's not published and the former is updated when the content is republished. Should I look at the workflowversionhistory?
You'd have to look through the workflow history for that document and get the initial publish state. If you don't want to do that (might be pretty messy and lengthy) you could always add a field to the page type for an initial publish date which will allow someone to add that date or default to when it is saved and not allow it to be editable after it is saved by using a macro on the enabled property of that field.
Related
I have a field on one of my base page types which I need to update programmatically from an external data feed, so that it can be included in my Smart Search index.
The documents are versioned, but I want to update the published value of this field regardless of checkout state, and obviously avoid any sort of overwrite when documents are checked in.
The field will not appear on the editor form -- or ideally, would conditionally display for Global Admins.
It appears that using the API to update the document without doing a CheckOut fails silently. However if I do a Checkout/Update/CheckIn on a checkout-out page, the author will lose their work I assume?
Any way to handle this "versionless" field via the Kentico data model and API?
I don't think there is a way around updating checked out pages. You can update the page type table directly, but as you mentioned, it will be overwritten when they check in. You could update the version history I believe to make changes to the current data that is checked out, but again, I think that will be lost if the user cancels.
The only way I can think of to solve your issue is to create another table that maps the values you want to the page. Then you don't have to worry about the pages being checked out, you just need to grab the documentID or something. Since the value isn't displayed to the editor, you just have a field that does a lookup on this table.
The preferred and right way is using the API but as you stated, it causes problems if a user has something already checked out and working on it or it's in workflow and not published yet.
If the field you're updating is page type specific, there is one thing specifically I can think of and that's going directly to the database to the page type's database field and perform an update to that field.
Note: this is not recommended unless you know specifically what you're doing and have done full testing on it
The down side of going direct to the database is this will not update the current version since you're using check in/out and workflow. You will also need to update the checked out and current version which means you need to:
Go to the Document itself in the cms_documents table and get the document you are working with.
Then using the fields DocumentCheckedOutVersionHistoryID and DocumentPublishedVersionHistoryID' you can get the version history IDs of the document from theCMS_VersionHistory` table.
Then you can perform an update to the CMS_VersionHistory and your custom page type fields.
You will then need to look in the CMS_WorkflowHistory table and find out if that document is in workflow and in what step.
After you have that workflow history step, use the VersionHistoryID field to go back to the CMS_VersionHistory table and update that record with your data.
Again, not an elegant solution since you are using check in/out and workflow but after some trial and error and testing you should be able to figure it out.
UPDATE
You may also be able to add a custom table or some other linked database table which will allow you to create a global handler. The linked table would be where you perform your updates via API and other calls without versioning or workflow. Then when a user updates a specific page type you could do a check to see when the last time that linked table was updated and update the field(s) you need on update of that particular page (of course by node and document IDs).
Unfortunately you'll have to check it in and out with API. See examples here.
Also you might need to publish it in order to reflect changes on the live site.
Basically what I want to do is create a form whilst within another form and pass values from the earlier form to the second. Complicated I know but here is what I got.
#Do(#Command([Compose];"LPK"); #SetField("PR_Make"; PR_Make))
The fields in both forms have the same name and this code is called when first document is attempted to be saved.
I think instead of editing the field on the second form it just saves a field as itself instead. Any help appreciated.
The best and common way is to enable form property "Formulas inherit values from selected document" in second form "LPK".
Add a default value formula to second form's fields you want to inherit and put just the name of field itself in. For your example default value formula it would be
PR_Make
Make sure you save document first and then create the new document.
Knut Hermann's answwer is the 'standard' way of achieving such things but there are other methods- eg you can use environment variables ..
Something like:
#Environment("PR_Make") := PR_Make;
#Command([Compose];"LPK");
Then set the default value for PR_Make in your new form as ..
#Environment("PR_Make")
FYI Environment variables are written to the user's Notes.ini file and so remain even after Notes has been closed and re-opened. #Environemt doens't work too well with Web applications as it uses the server's notes.ini.
An alternative would be to use profile documents:
#SetProfileField( "PRDefaults"; "PR_Make" ; PR_Make;#Username);
#Command([Compose];"LPK");
.. in the default field for PR_Make on new form :
#GetProfileField( "PRDefaults"; "PR_Make"; #Username);
Profile documents are stored as a kind of hidden document in the Notes database and persist with the database. The last parameter sets a further subdivision by username so each user gets their own profile doc - a bit like a personal profile for "PRDefaults". You can miss this last parameter #Username out, to have one profile doc per database but there's a risk of two people trying to use it at the same time and clashing.
Profile docs also work with web applications.
In CRM 2011, notes get automatically created and attached to main record on lost focus event. Requirement is to remove this auto save functionality. Only till main form is open user should be able to edit notes. And newly added notes should only get saved once main form is saved. For example, if user add one note and closes the browser or do not save the main form, then that note should not get attached to main record, new note should get discarded.
I was thinking following solution:
create new custom entity TempNotesHolder
Create 1:N relationship with the entity where we want this functionality, for example Case entity
Make actual case's note section read only(it is requirement, user don't want to edit/delete functionality for notes once note get created)
Write plugin for create event of Case and create one Record for TempNotesHolder and associate it with case(RegardingId field in TempNotesHolder = incidentId) This will ensure one Case will always have only one associated TempNotesHolder record. There is no way in CRM 2011 to ensure One entity record will have only one record in associated entity i.e. 1:1 relationship. At least I don't know the way. Let me know if any one are aware about it.
On Case form, add one IFrame below Case's note section
on case form load event, get TempNotesHolderId associated with case using fetchXml.(There is no actual field in Case entity that refer to associated TempNotesHolder, hence need to use fetchXml. Some how we can add associated TempNotesHolderId to Case entity, and place that field on Case form, make it hidden, to avoid fetchXml)
Prepare url to display only notes of TempNotesHolder record.(/_controls/notes/notesdata.aspx?EnableInlineEdit=false&EnableInsert=true&id=&ParentEntity=
Set this url to newly added IFrame, so notes of associated TempNotesHolder get displayed in IFrame. It will also have link "Add New Note".
User can add note to TempNotesHolder which are not directly added to Case record.
Next develop plugin on pre save event of Case and check if there are any notes added to TempNoteHolder, if yes move those notes to Case record, and delete notes for TempNoteHolderId. This way notes will get saved to main record only on main form save.
To handle browser close event after adding few notes to TempNotesHolder, write plugin on Case pre Retrieve event, check if any notes present for associated TempNotesHolderId, if present then delete those notes. (As notes are present on TempNotesHolderId, that means due to some reason these notes are not moved to actual case record and we no longer need them, so delete them. This will ensure on case load, TempNotesHolder note section always be blank)
The above solution was fine till step 8. When I tried to add notes in TempNotesHolder, it gave me error, "Record with does not exists in TempNotesHolder". Then I checked that GUID, I disappointed to know CRM is taking IncidentId when I create note for TempNotesHolder. Then I tracked down the actual code for create notes to find why it is taking IncidentId instead of TempNotesHolderId. I found following code in "_static/_controls/notes/notes.htc" function name "UpdateNote"
xml="0"+CrmEncodeDecode.CrmXmlEncode(value)+""+_parentCrmFormSubmit.crmFormSubmitId.value+""+this.parentEntityType+""+CrmEncodeDecode.CrmXmlEncode(currentTitle)+""+this.userId+""
CRM is taking _parentCrmFormSubmit.crmFormSubmitId.value as objectid while creating note.
Now I stuck with this problem. Any thoughts to overcome this show stopper issue are appreciated. Also any other alternate solution to main requirement are also welcome.
Pravin Pujari (Microsoft Dynamics CRM 2011 Developer)
I would suggest simplifying the solution as follows:
Add a field to Case called new_notetext.
Create a Plugin against the Pre-Create and Pre-Update messages on the Case entity.
In the plugin, take anything entered into new_notetext and add a note to the Case entity using that text. Then clear the field new_notetext so nothing is saved with the record.
Should work just fine and is much simpler to implement.
I work in a development/support team which has a shared Lotus Notes mailbox. We need to be able to associate an issue ID with each email. We started by adding this ID to the subject line (eg. "Something doesn't work [ID12345]"). For performance reasons, our IT dept don't allow indexing of shared mailboxes, so it takes a long time to search for a particular ID.
I decided to add a new ID field, which can be shown as a sortable column in views and folders. I put this field to the visible header (just below 'Subject') in the ($All) view and the ($Inbox) folder, and copied the ($Inbox) design to all the other folders in the database. That much was easy.
My problem is that when we reply or forward, this custom field is not carried over to the new memo, so we have to manually add it again before sending. And of course when the user responds, the field is again missing and must be manually added. I have searched the docs and the internet and haven't found any information on this. Either I have to declare this field as something which persists across replies and forwards, or I have to add a line somewhere which explicitly copies the field contents to the new memo.
fsw,
We do exactly this with our complaint system however our database is indexed although this should not be an issue to you. We created a view that is sorted by ID by extracting just the ID from the subject line, order it by ID and then by date descending. Base it on the $ALL folder view so you get both incoming and sent emails.
We then altered the memo form to include an embedded view single category of the new view that sits above the body which shows all other documents linked to the ticket.
This should avoid having to delve to far into the very complex mail template any further. One thing is to make sure you have a copy of the changes you made and a bit of doco re deploying as you can guarantee that one day your template will be completely overwritten in an upgrade and all your good work will be gone.
As the additional field would have to incorporated into all Memo forms in mail templates in your corporation and as these fields do not easily travel via SMTP, you should stick with the ID in the subject.
What you could do is to parse the subject (#Mid, #Right, ...) in the column formula in the view and only display the ID there (like you did with the additional field).
The other option I envision if having a field is required is to have an agent that processes the incoming message(reply) to have it parse out the issue ID from the subject and write it to the field. You could also do that with queryopen or postopen if running an agent is not possible
I'm currently writing an application that moves Notes documents between databases based on the amount of days that have elapsed from the creation/modified/last accessed dates. I would just like to get ideas on a simple and convenient way to create documents with specific dates, without having to change the time on the Domino server, so that I could test out my application.
The best way I found so far was to create a local replica and change the system clock to the date I want. Unfortunately there are problems associated with this method. It does not work on the modified date - I'm not sure how it is getting the modified date information when the location is set to Island (Disconnected) - and it also changes the modified and last accessed dates when the documents are replicated to the server replica.
Someone suggested trying to create a DXL of the document, modify the date time in the DXL file, then import it back into the database as a Notes document; but that does not work. It just takes on the date-time that it was created.
Can anyone offer any other suggestions?
You can set the created date for a document by setting the UNID (which is fundamentally a struct of timestamps, although the actual implementation has changed in recent versions). Accessed and modified times, though, would be unsettable from within the Notes/Domino environment, since the changes you make would be overwritten by the process of saving the changes. If you have a flair for adventure and a need to run with scissors, you could make the changes in the database file itself either programmatically from an external application, or manually with a hex editor. (Editing the binary will work -- folks have been using hex editors to clear the "hide design" flag safely for years. Keep in mind that signed docs will blow up badly, and that you need to ensure that local encryption is off for the database file.)
There's actually a very simple way to spoof the creation date/time: just add a field called $Created with whatever date/time you want. This is alluded to in the Notes C API header file nsfdata.h:
Time/dates associated with notes:
OID.Note Can be Timedate when the note was created
(but not guaranteed to be - look for $CREATED
item first for note creation time)
Obtained by NSFNoteGetInfo(_NOTE_OID) or
OID in SEARCH_MATCH.
Unfortunately, there's no analogous technique for spoofing the mod or access dates. At least none that's ever been documented, as far as I know.
I imagine given how dependent Lotus Notes is on timestamps (for replication, mainly), there isn't an API call that allows you to change the modified, created, or last access dates of a note. (More on the internals of Lotus Notes can be found here.)
I dug around the Notes C API documentation, and found only one mention on how to get/set information in the note's header, including the modified date. However, the documentation states that when you try to update that note (i.e. write it to disk), the last modified date will be overwritten with the date/time it is written to disk.
As an alternative, I would suggest creating your own set of date items within the documents that only you control, for example MyCreated, MyModified, and MyAccessed, and reference those in your code that moves documents based on dates. You would then be able to change these dates as easily as changing any other document item (via agents, forms, etc.)
For MyCreated, create a hidden calculated form field with the formula of #CREATED or #NOW. Set the type to computed when composed.
For MyModified, create a hidden calculated form field with the formula #NOW, and set the type to computed.
MyAccessed gets a bit tricky. If you can do without it, I suggest you live work with just the MyCreated and MyModified. If you need it, you should be able to manage it by setting a field value within the QueryOpen or PostOpen events. Problems occur if your users have only read access to a document - the code to update the MyAccessed field won't be able to store that value.
Hope this helps!