Lotus Notes NAB - Adding a field - lotus-notes

I have a project that I need to put an Internet Address and also add a new field called ShortName for all groups in the Notes NAB.
I am able to put the values and save the document , I tried with a doc.save and a computewithform. This is the Group form.
After the change, people in that group are no longer able to access the application.
Do you have an idea what I am doing wrong ?
User A is in group XYZ.
I added internetaddress xyz.com and a shortname text field xyzmigration
Application A is having an ACL with the group XYZ as editor. When User A tries to open the Application A, he get a not authorize. If I delete both values, User A is able to open the database.
Thanks for your help

$ServerAccess view validates Group documents and omits any Groups that has Shortname field present.

Normunds has the correct answer, but I want to add a suggestion: create a new group instead of modifying the existing group. I.e., if the group is "MyGroup", create a group named "MyGroup_Extended" and set it up with
Shortname = the value that you want
InternetAddress = the value that you want
Members = "MyGroup"
That way, you leave MyGroup untouched, but you still have a modified group document with the additional information added and the same member list.
And another thing: In order to make those groups that you already altered functional again, you should run a simple agent against all of the groups that does this:
FIELD ShortName := #DeleteField;
FIELD InternetAddress := #DeleteField;

After the help of some answers that I got here. I checked the view $ServerAccess. The selection formula is checking for a field Shortname and that is what was causing my problem. I will create another field name and we will be able to use this field instead of ShortName. allfields := #DocFields;
test1 := 0;
test2 := 0;
#For(i:=1; i < #Elements(allfields); i:=i+1; test1 := test1 + #If(#UpperCase(allfields[i]) = "LISTNAME";1;0));
#For(i:=1; i < #Elements(allfields); i:=i+1; test2:=test2 + #If(#UpperCase(allfields[i]) = "SHORTNAME";1;0));
SELECT (test1 < 2 & test2 = 0 &Type = "Group" & (#IsUnavailable ( GroupType)|GroupType="0" : "2":"3":"4")) & Form="Group" & #IsUnavailable($Conflict)
Thanks for your help.

Related

Whats the simplest way to find for a group of user all the group membership?

I do have one domino group (Access Control List only), lets call them Main_Group.
This group includes all employees, that I want to know on which other domino groups they are member of.
Members of Main_Group:
- John Smith/ORGANIZATION
- Peter Smith/ORGANIZATION
- Jeff Smith/ORGANIZATION
Of course this list is much longer then these 3 entries.
I would look for each member in this group, in which other domino group this user is member and put this information into a CSV. The CSV should have a format like this:
UserName;DominoGroups
John Smith;Domino_Group1,Domino_Group2,Domino_Group3
Peter Smith;Domino_Group2
Jeff Smith;Domino_Group1,Domino_Group3
Whats the best way to achieve to this information? Lotus Script, any View with formula? Or is there already a notes database is doing this?
It's not simple. A person can be in a group through one or more levels of indirection. I.e., a person is in GroupA and GroupA is in GroupB, and GroupB is in GroupC, and GroupC is in GroupD, and by the way GroupE, GroupF, and GroupG... You will have to write code to recursively traverse groups, detect cycles, and come up with a definitive list of group memberships. As far as I know, there's never been an API exposed for this.
There is no simple way to get what you want. You could create a view in the adressbook, use the "Group"- view as template and add one categorized column for the item "Members". Unfortunately -as Richard wrote- you will not get nested group memberships like that.
You would need to:
Cycle through all group documents
recursively get all members for every group
whenever your user is in the members, then add the group name to a list / an array...
export the result
BUT: If you just need to know / see what groups a specific user is member of, then use the Domino Administrator Client. Open the "Groups" View, then the "Groups" pane and select "Manage groups". Then select the user in the leftmost panel and click on "Member hierarchie" on the right side, then you see the groups that this user is member of, even nested ones. Unfortunately you cannot export this information.
This code builds a list of dynamic arrays to act as key/value pairs (where each value is an array). It's built from the Group view in names.nsf. Rather than taking each group name and loading up the members, it builds it the other way round so for each member, it has an array of groups. Groups can be in other groups so it runs through each group recursively. In order to prevent loops (e.g. where group A is in group B and vice-versa) it uses the visited array which terminates that part of the search if the group has already been visited. The visited array ends up, upon completion of the recursion, the list of groups the user is in.
Building the key/value List initially would be quicker than multiple full text searches, especially if, rather than looking up one name, you're looping all user names in names.nsf as once the key/value list is built there's no need to query the database again. I've not built the loop for each user but it could be added quite easily to the getGroupsForUser function.
Code below
getGroupsForUser function. Returns a formatted string of each group that a user is in. The user name is the first item.
Function getGroupsForUser(userName As String) As String
If userName="" Then Exit function
Dim ns As New NotesSession, namesDatabase As NotesDatabase
Dim visited As Variant, groupKeyValueStore List As Variant
Dim returnString As String, separator As String, i As Integer
Set namesDatabase = ns.getDatabase(ns.Currentdatabase.Server, "names.nsf", False)
visited = Null
Call getGroupKeyValues(groupKeyValueStore, namesDatabase)
Call searchGroupsRecursive(userName, visited, groupKeyValueStore)
i=0
returnString = ""
ForAll item In visited
If i=0 Then separator = ""
If i=1 Then separator = ";"
If i>1 Then separator = ","
returnString = returnString + separator + item
i = i + 1
End forall
getGroupsForUser = returnString
End Function
getGroupKeyValues loops through the Groups view in names.nsf and creates the key/value List.
Public Function getGroupKeyValues(groupKeyValueStore List As Variant , namesDatabase As NotesDatabase)
Dim groupView As NotesView, doc As NotesDocument, members As Variant, groupName As String
Dim separator As String, values As Variant, i As Integer, tempString(0) As String
Set groupView = namesDatabase.getView("Groups")
Set doc=groupView.Getfirstdocument()
Do Until doc Is Nothing
groupName = doc.ListName(0)
members = doc.getItemValue("Members")
ForAll member In members
If IsElement(groupKeyValueStore(member)) Then
If IsNull(ArrayGetIndex(groupKeyValueStore(member), groupName)) Then
values = groupKeyValueStore(member)
i = ubound(values) + 1
ReDim Preserve values(i)
values(i) = groupName
groupKeyValueStore(member) = values
End If
Else
tempString(0) = groupName
groupKeyValueStore(member) = tempString
End If
End ForAll
Set doc=groupView.getNextDocument(doc)
Loop
End Function
searchGroupsRecursive recursively searches each group, ensuring no group is visited twice.
Public Function searchGroupsRecursive(userName As String, visited As Variant, groupKeyValueStore List As Variant) As Variant
Dim length As Integer, userNotesName As NotesName, fullUserName As String
Dim tempArray(0) As String
Set userNotesName = New NotesName(userName)
fullUserName = userNotesName.Canonical
If IsNull(visited) Then
tempArray(0) = userName
visited = tempArray
Else
length = UBound(visited)
ReDim Preserve visited(length + 1)
visited(length + 1) = userName
End If
If Not isElement(groupKeyValueStore(fullUserName)) Then Exit function
ForAll item In groupKeyValueStore(fullUserName)
Call searchGroupsRecursive(CStr(item), visited, groupKeyValueStore)
End ForAll
End Function

SuiteScript Access Custom Field in Sublist

I have added two fields to the contact sublist record of customers. Two boolean values. I checked the values to make sure that they would show but in code cannot access those values in SS 1 or SS 2 through a sublist line item, I am accessing like this "var statements = rec.getLineItemValue( 'contactroles', 'custentity_statements', "1" );". When I look in the object for the customer record and look in the "contactroles" sublist, I cannot see those columns. If I load the contact record in SS 1 I can see the columns. Any help with this would be great, I would like to do it in SS 2 but I am flexible, thanks
Not sure whether this helps, but you can retrieve the contact id, then load the contact record and check the field value. This is assuming the custom field showing in the contact sublist is a contact field. The documentation isn't too swift, but it looks as though not all sublist fields are supported for getFieldValue. This is in SS1, but if it does what you want we should be able to take the same idea and write it in SS2.
var rec = nlapiLoadRecord('customer','11499');
var conId = rec.getLineItemValue('contactroles', 'contact', 1);
var con = nlapiLoadRecord('contact',conId);
var statements = con.getFieldValue('custentity9');
console.log(statements); //T

freeradius (MySQL config) adding custom attributes to the reply-item

I've run into a dead end while trying to set up customized attributes as a reply item (I want custom information added to the "access accept" packet).
While trying to achieve this I came across this entry:
# If you want to add entries to the dictionary file,
# which are NOT going to be placed in a RADIUS packet,
# add them to the 'dictionary.local' file.
#
# The numbers you pick should be between 3000 and 4000.
# These attributes will NOT go into a RADIUS packet.
#
# If you want that, you will need to use VSAs. This means
# requesting allocation of a Private Enterprise Code from
# http://iana.org. We STRONGLY suggest doing that only if
# you are a vendor of RADIUS equipment.
#
# See RFC 6158 for more details.
# http://ietf.org/rfc/rfc6158.txt
So I understand how the usual approach should be.
However my infrastructure is set up in stages and the radius server in question is already placed on the "inside", so I don't see why I shouldn't be able to set or overwrite unused attributes on both ends of this second internal authentication step.
Googleing around I found several threads on how to set this type of thing up with a users-file based approach on 1.x versions of Freeradius, not so much for any of the newer releases.
Is what I'm proposing still possible with freeradius-server-3.0.10 ?
And if so, how should I go about implementing this?
Current state:
I've added my attribute "faculty" to the dictionary (mapping the set integer from the DB to a string set in directory ie. Ei & MECH) and the respective DB, causing the radius server to find and evaluate the attribute set in "radreply" (here: := MECH) and "radgroupreply" (here += EI).
...
rlm_sql (sql1): Reserved connection (5)
(1) sql1: EXPAND SELECT id, username, attribute, value, op FROM radcheck WHERE username = '%{SQL-User-Name}' AND active > '0' AND active < '3' ORDER BY id(1) sql1: --> SELECT id, username, attribute, value, op FROM radcheck WHERE username = '*username*' AND active > '0' AND active < '3' ORDER BY id
(1) sql1: Executing select query: SELECT id, username, attribute, value, op FROM radcheck WHERE username = '*username*' AND active > '0' AND active < '3'ORDER BY id
(1) sql1: User found in radcheck table
(1) sql1: Conditional check items matched, merging assignment check items
(1) sql1: Cleartext-Password := "*password*"
(1) sql1: EXPAND SELECT id, username, attribute, value, op FROM radreply WHERE username = '%{SQL-User-Name}' ORDER BY id
(1) sql1: --> SELECT id, username, attribute, value, op FROM radreply WHERE username = '*username*' ORDER BY id
(1) sql1: Executing select query: SELECT id, username, attribute, value, op FROM radreply WHERE username = '*username*' ORDER BY id
(1) sql1: User found in radreply table, merging reply items
(1) sql1: faculty := MECH
(1) sql1: EXPAND SELECT groupname FROM radusergroup WHERE username = '%{SQL-User-Name}' ORDER BY priority
(1) sql1: --> SELECT groupname FROM radusergroup WHERE username = '*username*' ORDER BY priority
(1) sql1: Executing select query: SELECT groupname FROM radusergroup WHERE username = '*username*' ORDER BY priority
(1) sql1: User found in the group table
(1) sql1: EXPAND SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = '%{sql1-SQL-Group}' ORDER BY id
(1) sql1: --> SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = 'vid100' ORDER BY id
(1) sql1: Executing select query: SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = 'vid100' ORDER BY id
(1) sql1: Group "vid100": Conditional check items matched
(1) sql1: Group "vid100": Merging assignment check items
(1) sql1: EXPAND SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = '%{sql1-SQL-Group}' ORDER BY id
(1) sql1: --> SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = 'vid100' ORDER BY id
(1) sql1: Executing select query: SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = 'vid100' ORDER BY id
(1) sql1: Group "vid100": Merging reply items
(1) sql1: Tunnel-Type = VLAN
(1) sql1: Tunnel-Medium-Type = IEEE-802
(1) sql1: Tunnel-Private-Group-Id = "100"
(1) sql1: faculty += EI
rlm_sql (sql1): Released connection (5)
...
The keen observer will also notice some changes to the "radcheck" query, but this change is not related to the topic at hand.
So the Server gets the information, however I've not found a way to include it to the reply yet.
(1) Sent Access-Accept Id 81 from **IP-Radius-server**:*port* to **IP-supplicant**:*port* length 0
(1) Tunnel-Type = VLAN
(1) Tunnel-Medium-Type = IEEE-802
(1) Tunnel-Private-Group-Id = "100"
(1) Finished request
Any help or pointers would be appreciated :)
Felix
To anyone having similar problems.
I've come up with a workaround that works for me.
As described above it really is a lot of fuss to build a custom attribute.
What you can use though, is attribute 18 (Reply-Message) to convey information.
I went about this by adding to: .../raddb/sites-available/default in the "post-auth" section.
if (&reply:faculty && &request:NAS-IP-Address == *IP-WEBSERVER*) {
update reply {
Reply-Message += "Faculty: %{reply:faculty}"
}
}
Which adds "faculty" information if it can be found in either the radreply or the radgroupreply if and only if the supplication comes via the sepcified "webserver". Using the freeradius operator arithmetic you can also weight the reply (for me: radreply := radgroupreply +=).
This works well for freeradius3.0.10.
I consider this thread closed - Felix
You need to define your custom attribute as a VSA (Vendor specific attribute). Attributes above 255 in the standard RADIUS dictionary will not be encoded in proxied requests, or in replies, that is because the attribute field is only 1 byte wide.
If you want to do it properly you'll need to request an IANA PEN (Private Enterprise Number) http://pen.iana.org/pen/PenApplication.page for your organisation (after checking there isn't already one assigned http://www.iana.org/assignments/enterprise-numbers/enterprise-numbers).
You can then define your own vendor dictionary, and add your own attributes with numbers between 1-255.
Here's a nice short one you can use as an example: https://github.com/FreeRADIUS/freeradius-server/blob/v3.1.x/share/dictionary.bt
You don't need a separate file for your vendor dictionary, you just need to copy the relevant lines into raddb/dictionary.
If you don't care about doing it properly, look through the PEN assignments to find a defunct company and use their PEN.

How to associate id and its value in Combobox Domino designer(lotus script)

I am new to Domino designer and lotus script,
I have a form ,which has a combobox ,In combobox I have a formula for combobox:
(#DbColumn("" : "NoCache"; ""; "myview"; 2)
now I want to associate the ID and its name
Example : id :1 name(to display in combo) :Benz
id :2 name : Fiat
id :3 name : Yamaha
now my combobox must display only fiat,yamaha,benz but the corresponding id must be saved (not the name)
currently I'm displaying only names and saving names(I want to link it to id)
How can I achieve this ?
Your view needs to contain the values in format Name|ID (this is a pipe sign) in order to achieve what you want.
Column values:
Benz|1
Fiat|2
Yamaha|3
Response to your comment: Best practice (performance- wise) is, to create a separate column in your view with the formula Name + "|" + ID (you can hide it, if you use the view for users AND DBColumn, what would be bad practice by the way).
if you don't want to do this, then your formula could look like this:
_names := #DbColumn("" : "NoCache"; ""; "myview"; 2);
_ids := #DbColumn("" : "NoCache"; ""; "myview"; 1);
_names + "|" + #Text(_ids)
You REALLY should take a training in Lotus Notes Design, as these are all basics, if you once understood how Notes works.
The formula above is bad in a lot ways:
Usage of "NoCache" is a real performance- killer. Don't do it in big applications
doing two lookups instead of one doubles your response- times
Every lookup HAS to have an error handling, otherwise your form will not open anymore, if there is an error in it.
If the return of your DBColumn is >32k of data (large lists) this whole thing will fail due to field restrictions in Lotus Notes
A "best practice" way to do this (ignoring the possible 32k error) would be:
Create a view with a (hidden) third column with formula Name + "|" + ID
Use this code:
_view := "myview";
_col := 3;
_lkp := #DBColumn( "" : "Cache" ; "" ; _view; _col );
#If( #IsError( _lkp ) ; "" ; _lkp )

Get members of a group in Lotus Domino

I retrieve names from a group using formula, and put them in a field of type Names this way:
#Name([CN];NAME)
I want to manipulate this data in my code, but using Lotusscript. Can't find it at Google or Lotus Domino's Help. Is there a way I can handle this?
In LotusScript there is a class named "NotesName" to do such manipulations.
If there is a field named "NAME" in you document, then the code would look like:
Dim doc as NotesDocument
Dim nnName as NotesName
'Somehow get the document, using ws.CurrentDocument.document
'or db.UnprocessedDocments.GetFirstDocument, depends on your situation
Set nnName = New NotesName( doc.GetItemValue("NAME")(0) )
Whatyourlookingfor = nnName.Common
If NAME is a Multivalue then you would have to write a loop to get the common- name for every element in the array doc.GetItemValue("NAME")
The next time you have a question, check out the language cross reference in the help...
There it tells you, what the LotusScript- Pendant for #Name is.
Please try with below suggestion for getting list of person names from group.
First need to check the availability of searching group on names.nsf (All the groups are available on "($VIMGroups)" view.
if the group is available means you need to get the list of values from "Members" item
The members item have variant(list) values. So need to iterate the members for getting each value
Please refer the below sample code:
Set namesDb=session.GetDatabase(db.Server,"names.nsf")
Set groupVw=namesDb.GetView("($VIMGroups)")
Set groupDoc=groupvw.GetDocumentByKey("groupname")
persons= groupDoc.members
Forall person In persons
Msgbox person
End Forall
You can use the Evaluate method. It will return you the result of a Notes Formula:
Dim result as Variant
formula$ = "#Name([CN];NAME)"
result = Evaluate(formula$)
If the formula needs to be evaluated within the context of a document, you can pass that document as a second parameter to the method.
More info here

Resources