Restricting access in Lotus Notes form - lotus-notes

I would like to be able to let all users to create a form (QCR) but then no one should be able to edit the form except me and one other user. I have been tinkering around with the ACL and Authors and Readers field but have no luck.
Some more background:
1. This form is created by clicking a button from a separate database because some of the information in this QCR form are inherited from that database.
2. Users in the All group should be able to create this form
3. The users should be able to read all the documents in the QCR database but not edit them
4. I and one other users should be able to to read and edit all the documents
5. There are some codes in the QuerySave event to compare the value before and after a documents is being edited
What I have tried:
I created a group QCR_Access that has me and 1 other user as members. Then I created an Authors field, computed, with 'QCR_Access' as the Formula in the QCR Form. But no matter what kind of Access type that I gave to the All group (Depositor or Author), the application keeps giving me error whenever I tried to save a new document in the database with one of the user in the ALL group.
Below is the codes in the Querysave, might help give you some idea what I am doing.
Sub Querysave(Source As Notesuidocument, Continue As Variant)
' Compare the values in the form after it is saved with its original values when the document is not a new document.
Dim doc As NotesDocument
Set doc = Source.Document
Dim session As New NotesSession
Dim user As String
user = session.CommonUserName
If newDoc Then
doc.Log_Date = Cstr(Now())
doc.Log_User = user
doc.Log_Actions = "New document created."
Else
' Load fields value to the array
lastValues(0) = doc.QCR_Requestor(0)
lastValues(1) = doc.QCR_No(0)
...
lastValues(31) = doc.QCR_Tracking_Info(0)
' Compared each value in the array to see if there is any difference
Dim i As Integer
For i = 0 To 31
If lastValues(i) <> originalValues(i) Then
Call UpdateLogFields(doc,user,i)
End If
Next
End If
End Sub
Sub UpdateLogFields (doc As NotesDocument, user As String, i As Integer)
Dim logDate As NotesItem
Dim logUser As NotesItem
Dim logActions As NotesItem
Set logDate = doc.GetFirstItem("Log_Date")
Set logUser = doc.GetFirstItem("Log_User")
Set logActions = doc.GetFirstItem("Log_Actions")
' a space is needed otherwise the appended text is right next to the border
Call logDate.AppendToTextList(" " & Cstr(Now()))
Call logUser.AppendToTextList(" " & user)
Select Case i
Case 0: Call logActions.AppendToTextList(" Requestor is changed.")
Case 1: Call logActions.AppendToTextList(" QCR No is changed.")
...
Case 30: Call logActions.AppendToTextList(" Follow Up information is changed.")
Case 31: Call logActions.AppendToTextList(" Tracking information is changed.")
End Select
End Sub

I think you must definitely use authors field here, your description fits exactly for purpose... I would recommend you to use a role in this case thought, because that way you can assign it to someone else in emergencies or if you leave the company...
If you ACL is correctly setup, the you only need to add the value of the role like this in your authors field "[role]" I have attached a link with an image that shows how should your field look like if you inspect it.
http://bp1.blogger.com/T-j3ZLqfNQ/RsQXnWk20uI/AAAAAAAAAic/RBRJdD-wVs4/s1600-h/0.gif
Also, consider that if you write names to an authors field, the you need to use the fully qualified name of the people, otherwise it wouldn't work

If I'm following correctly, the members of the ALL group that are having trouble saving the QCR form, are the ones that are not in the QCR_Access group, correct? That would make sense given that the computed Authors field on the QCR form is set to only allow QCR_Access editing access.
The fix, then, would be to update that document's author field after the user has saved it. You could do that with some sort of agent that runs under a higher-privileged user account. You could also perhaps "hide" the document from the user who creates it until that agent runs, using a reader field.
It's been a while, but I think I opted for a lower-security solution when I faced this, essentially using form events to prevent editing. In that case you can prevent editing when the document is not new, and when the user is not in a certain group. You have to handle the QueryOpen and QueryModeChange events and put the logic there. NOTE: This isn't real security. Authors and Readers fields are the recommended way to handle security for a document.
Hope this helps!

You could make the formula for your authors field look like this:
#If(#IsNewDoc;"All";"QCR_Access");
There is one problem with this, however. If a regular user creates the document, saves it but does not close it, then tries to make changes and save it again, the second save will fail. To deal with that, you could give the users Depositor access and having your querySave code check the Database.CurrentAccessLevel property to see if the current user has Depositor access and prompt the user to ask "Are you sure you want to save? You will not be able to make additional changes."

Create two ACL groups in the Domino Directory (e.g.):
QCR_Editors
QCR_Creators
Put everyone into QCR_Creators, put just yourself and the other editor into QCR_Editors.
In the database access control list (ACL):
Give QCR_Editors "Editor" access (with "Delete documents," if needed.)
Give QCR_Creators "Author" access (with "Create documents" only.)
Note:
You do not need to use Authors or Readers fields on the form or documents.
Creators will have only one oportunity to save the document. Once it is saved, they will be locked out from further edits.
If you need additional functionality (like permitting several saves until done,) let me know.
-- Grant

Related

Lotus Notes - Script or formula to create multiple new documents within a database

I have the following situation:
currently an end user needs to create several documents using a step by step process, but with some new features that was created, the user will need to create more required documents.
I am afraid they will forget to create an important one that will mess the process at the end.
Based on this I was thinking to create a script, since the Compose #Command (Formula Language) allows me to create only one form.
Note that these documents will have computed fields, so no need to fill any data on these new forms.
Here is what I got so far, it is working but I think someone could give a better idea. Thanks.
Dim session As New notessession
Dim db As notesdatabase
Dim newdoc As notesdocument
Dim i%
Set db=session.currentdatabase
For i%=1 To 1 'or however many slots you want
Set newdoc=db.createdocument
newdoc.form= "Form1"
Call newdoc.save(True,True)
Set newdoc=db.createdocument
newdoc.form="Form2"
Call newdoc.save(True,True)
Set newdoc=db.createdocument
newdoc.form="Form3"
Call newdoc.save(True,True)
Next i%
End Sub
If you want to make the documents compute as if they were opened in frontend, then you need to tell the code to do that: simple saving a document does NOT do frontend calculations. You need to add a ComputeWithForm before every save to do exactly that: compute the document with the assigned form. That will look like this:
Set newdoc=db.createdocument
newdoc.form= "Form1"
Call newdoc.ComputeWithForm( True, True )
Call newdoc.save(True,True)
Take care: if there is any error in the formulas of your form because you forgot to fill some essential field, then the compute will not complete and only fields above the one that had the error will be calculated. In addition this funcion may throw an Error if something goes wrong that you have to catch in your code (depends of parameters, check documentation)

Override Authors Field and allow access to some fields. Lotus Notes

I have a Notes Form containing many fields, tabbed tables, embedded views etc. Editing access is restricted to a small group via an Author field and the ACL to prevent changes to most of the data. However, I also need to allow editing of one or two fields to a wider user group. In essence the opposite to what one can do with Controlled Access Sections.
A move to XPages on this one is not a realistic option in this instance.
I know it is probably a non-starter but any help would be appreciated.
I would also follow the path that Richard describes in his respons, but without the delay. Write an agent, that Runs on behalf of a person / server who is allowed to edit everything in that database.
Then create a form that you open in a dialog that the user can fill and call the agent with runonserver.
Example code might look like this:
Dim ws as New NotesUIWorkspace
Dim ses as New NotesSession
Dim db as NotesDatabase
Dim ag as NotesAgent
Dim docTmp as NotesDocument
Dim strID as String
Dim varOK as Variant
Set db = ses.CurrentDatabase
Set ag = db.GetAgent( "RunMeOnServerOnBehalfOfSomeone" )
Set docTmp = new NotesDocument( db )
call docTmp.ReplaceItemValue( "ChangeUNID", docToEdit.UniversalID )
varOK = ws.Dialogbox( "YourSpecialDialogForm", True, True, False, False, False, False, "Enter values", docTmp, True, False, True )
If not varOK then exit sub
Call docTmp.Save( True, True, True ) '- runonserver cannot be called with a notesdocument that is unsaved
strId = docTmp.NoteID
Call ag.RunOnServer( strID )
In the agent you read the unid of the document to change and write the values from the docTmp to the target document.
Don't forget to cleanup the docTmp in the agent or in the code later.
of course you can use "reusable" parameter documents or one document per user. depending on how often this function ist needed.
But this seems to be a bit of a stretch (you need to keep track in your agent WHO requested a change, as all documents will be saved by the signer of the agent and not the user himself.
Probably a better solution would be to ADD the users to the author- field of the document and simply PROTECT everything else in the document with access controlled sections. You can completely hide those section headers and everything so that nobody can collapse them or if you don#t like the look of them.
There's no way to allow users without Author access the ability to directly edit part of the document. The only option I can think of would be to give them the ability to click a button that allows them to type their changes into a new temp document (using a form that only contains the fields that you want to expose), and set up an agent that runs when docs are created or modified that reads those documents copies the data from them back into the original document. There can be a bit of a delay before the changes are applied, though, so you'll have to warn users of that.

Xpages only passes first character to Agent

I have created an Xpage to allow the administrator to input a single Notes Document (They are Contracts) ID into an edit box and press a button to delete the Contract. The delete calls an Agent passing the Contract ID. Below is the button script and then the relevant part of the Agent. What is happening is only the first character is being passed to the Agent, i.e if the Contract ID is 9MXCB4 only "9" is being passed as the Agent message box prints this to the log. What am I doing wrong here? If I hard code a Contract ID after the message box the Contract is processed correctly.
Button code
ag = database.getAgent("DeleteOneContract");
noteid = getComponent("ContractIDDelete").getValue()
ag.run(noteid)
Part of Agent code
Dim runAgent As NotesAgent
Dim deleteID As Variant
deleteID = runAgent.Parameterdocid
MsgBox "Input is " & deleteID
'If line below is uncommented it processes the Contract correctly
'deleteID = "9MXCB4"
' Rest of agent process
....
Note that I have also tried runAgent.Target and runAgent.Query
Just tested that and when I pass it a valid NoteID, the agent reads it just fine. I don't think you can pass any other value than a NoteID to the agent this way.
An alternative might be to use the agent.runWithDocumentContext(doc) method and retrieve the document before sending it to the agent.
I believe that the note ID parameter has to actually be a hexidecimal number in string form. It doesn't have to line up with an actual note ID in the database, but it can only contain 0-9 and A-F (with presumably a cap on size).
To add an extra thought on Jesse's and Mark's correct answers: from AJF's question we cannot tell whether the Xpage is bound to an actual NotesDocument object, or whether it is a (temporary) stand-alone page. In that case, of course, agent.runWithDocumentContext won't work.
But unless you have a good reason to perform the rest of your task using a LotusScript coding: why use an agent in the first place? Why not perform the deletion directly using SSJS code? On the Xpages side of the process you most probably will have to start with SSJS code very similar to Mark's example, but then why not go ahead and finish it off with two or three more lines?
In fact I try to avoid calling agents directly from my Xpages driven applications, due to performance issues, and because I don't like my code to be scattered all over the place.

Lotus notes - error accessing shared private on first use view from LotusScript

Good morning,
I have develop a note application which is used to make a booking. This application is used by multiple user at the same time.
I am quiet new to this development and now I would like to develop a functionality so that user can print a export data to excel.
I have created a view (Shared) where its Selection Formula is base on critical each user specify in a search form. I have problem when a user is being printing and yet finished, the other users is also clicking printing same time, the result of export data on the sides are the same to the one who created first.
I was thought may be using the kind of (Shared, Private on first Use View) but it generated an error [Notes error: Index is not to be generated on server ("view name") ] at the points where I called
view.Clear
view.SelectionFormula = formula
uiw.ViewRebuild
I have no idea how to solve this problem. Could you please advice how this problem could be solved?
Thanks your in advance for your great help.
Best regards,
Veasna
There are different ways to do this. One possibility is to use a "shared, private on first use" (spofu) view: then every user gets his own copy of the view, and they don't impact each other. But I think it is not a good idea to do it like that, as every user needs designer rights to change the selection formula of the view. This is something you do not want.
A better way would be to use a spofu folder for each user and put the documents in it like this:
Dim ses as New NotesSession
Dim db as NotesDatabase
Dim dc as NotesDocumentCollection
Dim folder As NotesView
Dim formula as String
Set db = ses.currentDatabase
Set folder = db.GetView("NameOfTheSpofuFolder" )
'Make it empty
Call folder.AllEntries.RemoveFromFolder("NameOfTheSpofuFolder")
'Search documents based on the formula
Formula = "Field1 = 2 & Field2 = 5"
Set dc = db.Search( formula, Nothing, 0)
Call dc.PutInFolder("NameOfTheSpofuFolder")
Spofu folders need a little "care" but usually they work quite nicely.
This code is not tested and just written down without syntax check etc. It might contain typos, but should give you an idea how to start.
You could create a Lotusscript agent to export the data the users specify.
Get the search criteria from the form, then use db.Search or (preferably) db.FTSearch to get the documents to export.
Now you can export the data of those documents to Excel, using one of the techniques described here:
http://blog.texasswede.com/export-from-notes-to-excel-3-different-ways/
If you want to export as CSV, you can use this code as a start: http://blog.texasswede.com/export-notes-view-to-excel-with-multi-value-fields/
According to this thread on the Notes 6/7 forum, there may be a workaround for this problem. You haven't shown enough code to know for sure. If you are using getView() to access the Shared - Private On First Use (SPOFU) view, that doesn't work. The workaround is to loop through the db.Views() array, checking both the Name and Readers properties in order to make sure that you get a handle on the private instance of the view instead of the shared instance.

Difference in doc created by agent vs gui QuerySave fails to allow ODBC transfer

After I create a doc in a Notes app, I'm moving information from that doc to a postgres db.
The agent that transfers the data to postgres uses a field in the doc as the key field.
I'm running into the following problem:
- If I create the doc via the Notes client, the transfer occurs without problems.
- If I create the doc from an agent (which processes an incoming email and generates a valid key field value), the transfer fails with a null key error. If I then open and save the doc, the transfer is successful.
I key field value is not null, however. I can see it in the view, in the document, and in the document properties.
Any thoughts on how I might be able to figure this out would be appreciated.
thanks!
clem
============================
Thanks Torsten for the reply. I appreciate it. Well, there's not much to the code, really. Here's part of it. "x.LogNumber" returns a string. The format is something like T1234CP. I ended up adding the computeWithForm and setting the IsSummary tho I don't think it was necessary.
atdoc.logNumber = x.LogNumber
Call atdoc.computeWithForm(false, false)
Dim lnItem As NotesItem
Set lnItem = atDoc.getfirstitem("logNumber")
lnItem.IsSummary=True
Call atdoc.save(True, False)
=======================================
Once the doc is created, an agent runs that transfers some data from the doc to the postgres db via odbc:
'.. define the 'key field' to be use in the connection.select call
Dim selectFldLst As New LCFieldList
'.. add the key field name to the LCfieldList object.
Call selectFldLst.Append(NotesKeyFieldName, LCTYPE_TEXT)
'.. set this field to be the key field.
selectFldLst.Getfield(1).flags = LCFIELDF_KEY
Set Notes_LCFieldList = New LCFieldList ' flSrc
Set odbcDB_LCfieldList = New LCFieldList ' flDest
'.. get the key of the doc to transfer.
Set docWithTransferID = docsToTransferViewEntry.Document
selectFldLst.LogNumber = Trim(docWithTransferID.stid(0))
count = Notes_LCConnection.Select(selectFldLst, 1, Notes_LCFieldList)
^--- This selects the fields from the Notes document. This is where it fails. It returns 0 for 'count'. It should return 1. If I save the document manually, it works.
Sounds like your form is doing something to it. As a quick and dirty fix you could try doc.computeWithForm() in your agent before saving.
You create the records from Notes? Save yourself the trouble with code in the events and configure DECS. It creates the document for you reliably.
Most probably the items in the document you create do not have the "Summary" property set. That makes them "invisible" for some functions / subs...
Please provide some code about how you create the items. If you do it like Set item = New Item(doc, "Name", "Value") then the item will not be summary. Then you need to call a item.issummary = true
Taking into account the last comments I guess, that the agent sets the item with the wrong datatype. Again: The code of the agent would have helped to identify this.
If for example the Field in the document is of type text and the agent writes something like
docWithTransferID.stid = 1 then everything "seems" to be OK, as the field is shown correctly in the views and in the Form. But in the Properties of the document it will be shown as number. As soon as you save the document, the design of the form will force it to be a Text.
The same thing works vice versa. If the agent reads the data from a textfile (e.g) and does something like docWithTransferID.stid = "1", then the item will be text, no matter how it is defined in the Form. As soon as you save the document -> Voila, it will be a number again.
Background LotusScript does not know ANYTHING about the Form and therefor does not obey datatypes or formats... You have to take care for this yourself.

Resources