2025/09/24

共通部品にチャレンジ:#5)LotusScript 実行ログ - ログの出力(Print* 関数)

#3 から開始したライブラリ作成作業の続きです。今回はログを出力する関数 3 つを紹介します。


◇ 通常ログの出力(PrintLog 関数)

最初は通常のログを出力する PrintLog 関数です。xPrintLog 関数でログの出力を行っているのですが、この関数の役割は、エラーチェックと出力した通常ログのカウンタのインクリメントとなっています。

Public Function PrintLog(ByVal vsLogText As String) As Boolean
   If xbIsInit = False Then Exit Function
   If xbIsOpen = False Then Exit Function

   '通常ログとして、引数の文字列を出力
   If xPrintLog(False, vsLogText) Then
      PrintLog = True

      'カウンタインクリメント
      xlMessage = xlMessage + 1
    End If
End Function


◇ エラーログの出力(PrintError 関数)

通常ログと違い、エラーログの出力は、エラーメッセージを記録するフィールド LogError にエラーメッセージを記録して、エラーフラグ IsError に "1" をセットしています。

Public Function PrintError(ByVal vsErrorMessage As String) As Boolean
   If xbIsInit = False Then Exit Function
   If xbIsOpen = False Then Exit Function

   'エラーログとして、引数の文字列を出力
   If xPrintLog(True, vsErrorMessage) Then
      'エラーメッセージを記録
      xndLog.LogError = vsErrorMessage
      'エラーフラグを記録
      xndLog.IsError = "1"

      PrintError = True

      'カウンタインクリメント
      xlError = xlError + 1
   End If
End Function


◇ サマリーの出力(PrintSummary)

「8 件の文書を処理しました。」というような処理結果を出力する機能がサマリーです。エラーと同様に専用のフィールド LogSummary にメッセージを記録します。それ以外の処理は通常ログと同じです。

Public Function PrintSummary(ByVal vsLogSummary As String) As Boolean
   If xbIsInit = False Then Exit Function
   If xbIsOpen = False Then Exit Function

   '通常ログとして、引数の文字列を出力
   If xPrintLog(False, vsLogSummary) Then
      'サマリを記録
      xndLog.LogSummary = vsLogSummary

      vsLogSummary = True

      'カウンタインクリメント
      xlMessage = xlMessage + 1
   End If
End Function


◇ ログ出力の本体

この関数がログメッセージを出力する本体で、上記 3 つの関数からコールされています。引数 vbIsError が True の場合はエラー、False の場合は通常ログを表します。

Private Function xPrintLog(ByVal vbIsError As Boolean, ByVal vsMessage As String) As Boolean
   '通常ログのスタイル適用
   Call xnrti.AppendParagraphStyle(xnrtpsMsg)

   '日時
   Call xnrti.AppendStyle(xnrtsDT)
   Call xnrti.AppendText(Format(Now, "yyyy/mm/dd hh:nn:ss"))

   'ログ(メッセージ)
   If vbIsError Then
      '通常ログ
      Call xnrti.AppendStyle(xnrtsErr)
   Else
      'エラーログ
      Call xnrti.AppendStyle(xnrtsMsg)
   End If
   Call xnrti.AddTab(1)    '日付とログの間
   Call xnrti.AppendText(vsMessage)

   xPrintLog = True
End Function

処理の流れは、段落スタイルをセットして、日付とログメッセージを出力しています。文字色を変えるため出力前に AppendStyle であらかじめ定義したフォントを指定しています。メッセージの出力ではエラーかどうかに応じてフォントを切り替えています。


前回 共通部品にチャレンジ


2025/09/23

共通部品にチャレンジ:#4)LotusScript 実行ログ - ログの開始(LogOpen 関数)

前回から開始したスクリプトライブラリ作成作業の続きです。今回はログ出力を開始する処理に関して記載します。


◇ ログの開始(LogOpen 関数)

まず、ライブラリ利用者とのインターフェースとなる LogOpen 関数です。初期化できていない場合とすでに Open 済みの場合はキャンセルするエラーチェックをしてから、処理を行います。

ログ DB に新規文書を作成し、ログ文書の初期化(後述)を行い、フラグや戻り値を整えています。

Public Function LogOpen(ByVal vsLogTitle As String) As Boolean
   Dim s As String

   On Error GoTo Err_General

   If xbIsInit = False Then Exit Function
   If xbIsOpen = True Then Exit Function

   'ログ文書の作成
   Set xndLog = xndbLog.CreateDocument()
   xndLog.Form = "fStdLog"

   'ログ文書の初期化
   Call xInitLog(vsLogTitle)

   '終了処理
   xbIsOpen = True
   LogOpen = True

   '処理開始メッセージの出力
   Call PrintLog(xcsLibName & |: ログ出力の開始 (| & xcsLibName & | | & xcsLibVersion & |)|)

   Exit Function

Err_General:
   s = "LogOpen でエラーが発生しました。" & Chr(10)
   s = "問題を解決するまでログ出力はできません。" & Chr(10)
   s = s & Error$ & " (Err = " & CStr(Err) & ", Erl = " & CStr(Erl) & ")"
   MsgBox s, 16, xcsLibName
   Exit Function
End Function

最後に PrintLog をコールして、ログの開始とライブラリのバージョンを記録します。この関数はログを出力する関数なのですが、これについては次回紹介します。


◇ ログ文書の初期化

xInitLog はログの基本情報を文書にセットする関数です。ログの開始時刻、エージェントの情報、ユーザ名や DB の情報を記録しています。

Function xInitLog(ByVal vsLogTitle As String)
   Dim na As NotesAgent
   Dim sTitle As String
   Dim v As Variant
   Dim sName As String

   '初期化
   sTitle = vsLogTitle
   sName = xns.UserName

   '開始日時
   xndLog.LogStartTime = Now

   'エージェント情報
   Set na = xns.CurrentAgent
   If Not(na Is Nothing) Then
      'エージェントと別名を分離
      v = Split(na.Name, "|")
      xndLog.AgentName = xRemoveFirst(v)    'エージェント名
      xndLog.AgentAlias = v                                     'エイリアス名

      'タイトルの指定がない場合、エージェント名をセット
      If sTitle = "" Then
         sTitle = xndLog.AgentName(0)
      End If
   End If

   'ログタイトル
   xndLog.Title = sTitle

   'ユーザ名
   xndLog.UserName = sName

   'サーバエージェント
   If xns.IsOnServer Then
      xndLog.IsOnServer = "1"
   End If

   'DB情報
   xndLog.DBTitle = xndbCur.Title
   xndLog.Server = xndbCur.Server
   xndLog.FilePath = xndbCur.FilePath

   'リッチテキスト準備
   Set xnrti = xndLog.CreateRichTextItem("Body")

   'フォントの準備
   Call xInitFont(xnrti)
End Function

また、リッチテキストフィールドを作成して、ライブラリ内の Private 変数に格納しています。このフィールドは、さまざまなシーンで利用するのでライブラリ全体からアクセスできるようにしています。


◇ エージェント名と別名を分離

NotesAgent クラスの Name プロパティは別名を含めて "|" 区切りで返します。そこで Split 関数で配列化した後、xRemoveFirst 関数でエージェント名と別名を分離しています(前述の xInitLog  関数の下記部分)。

Private Function xInitLog(ByVal vsLogTitle As String)
   Dim na As NotesAgent
         ・・・
   'エージェント情報
   Set na = xns.CurrentAgent
   If Not(na Is Nothing) Then
      'エージェントと別名を分離
      v = Split(na.Name, "|")
      xndLog.AgentName = xRemoveFirst(v)    'エージェント名
      xndLog.AgentAlias = v                                     'エイリアス名
         ・・・
 End Function

xRemoveFirst 関数は、引数の配列から最初の要素を削除(引数の配列を更新)し、削除した要素を戻り値として返します。

Private Function xRemoveFirst(rvArray As Variant) As Variant
   Dim i As Integer

   '最初の要素を戻り値にセット
   i = LBound(rvArray)
   xRemoveFirst = rvArray(i)

   '各要素を1つ前に詰める
   For i = LBound(rvArray)+1 To UBound(rvArray)
      rvArray(i-1) = rvArray(i)
   Next

   '最大要素番号を1つ減らす
   If LBound(rvArray) = UBound(rvArray) Then
      '要素が一つなので初期化
      ReDim rvArray(UBound(rvArray))
   Else
      ReDim Preserve rvArray(UBound(rvArray)-1)
   End If
End Function


◇ フォントの準備

ログ文書の初期化の最後でコールしている xInitFont 関数はログ出力で利用するフォント情報を初期化する関数です。今回のログ出力では、項目ごとにフォントを切り替える仕様としています。頻繁にアクセスするので、フォント情報もライブラリ内の Private 変数に格納します。

Private Function xInitFont(vnrti As NotesRichTextItem)
   Dim sFont As String

   sFont = "メイリオ"

   '通常のメッセージ
   Set xnrtsMsg = xns.CreateRichTextStyle()
   xnrtsMsg.NotesColor = 0     '黒
   xnrtsMsg.FontSize = 10
   xnrtsMsg.NotesFont = vnrti.GetNotesFont(sFont, True)
   xnrtsMsg.Bold = False

   'ログ時刻
   Set xnrtsDT = xns.CreateRichTextStyle()
   xnrtsDT.NotesColor = 15    '薄いグレー
   xnrtsDT.FontSize = 10
   xnrtsDT.NotesFont = vnrti.GetNotesFont(sFont, True)
   xnrtsDT.Bold = False

   'エラーメッセージ
   Set xnrtsErr = xns.CreateRichTextStyle()
   xnrtsErr.NotesColor = 2     '赤
   xnrtsErr.FontSize = 10
   xnrtsErr.NotesFont = vnrti.GetNotesFont(sFont, True)
   xnrtsErr.Bold = True    ’太字
End Function

通常のメッセージは黒、エラーは太字の赤字として目立たせています。また、ログの出力時刻はさほど重要ではないのでグレーとしています。

なお、フォントをセットする(NotesFont プロパティ)ためにリッチテキストフィールド(NotesRichTextItem オブジェクト)が必要です。文書を作成してからでないと利用できないため LogOpen 関数コール時に初期化しています。


前回 共通部品にチャレンジ


2025/09/22

共通部品にチャレンジ:#3)LotusScript 実行ログ - ライブラリの使い方と作成

LotusScript 実行ログ出力機能作成の 3 回目です。いよいよスクリプトライブラリの作成を始めます。ライブラリの使い方を整理してから、ライブラリのコーディングを始めます。


ライブラリの使い方

LotusScript 実行ログを出力する機能は、スクリプトライブラリにまとめます。アプリの開発者は、自身が作成するエージェントやフォームのボタンなど、アプリケーション内でこのライブラリを利用して、処理状況や実行結果をログ DB に残します。開発者は、ログ管理に関しては部品を利用するだけとなるため開発効率が上がるというのが狙いです。

ライブラリのインターフェースとなる関数と機能は以下の通りとなります。

LogOpen ログの記録を開始
PrintLog ログ(通常のメッセージ)を記録
PrintError エラーログを記録(赤字で目立つように記録)
PrintSummary 処理結果のサマリを記録
LogClose ログの記録を終了し、ログ文書を保存

LogOpen でログの記録を開始、Print* でログの中身を出力、LogClose でログ DB に文書として保存して終了します。NotesLog クラスとメソッド名は違いますが、使い方の流れは同じですね。


ライブラリの作成と初期化

新規で LotusScript のライブラリを作成します。

名称 StdLog

まずは、ライブラリの初期化に関連する部分を紹介します。


◇ ライブラリの定義

ライブラリの定義にあたる (Options)、(Declarations) は次の通り記述します。

Option Declare

Private xns As NotesSession
Private xndbCur As NotesDatabase
Private xndbLog As NotesDatabase
Private xndLog As NotesDocument
Private xnrti As NotesRichTextItem

'ライブラリ情報
Private Const xcsLibName = "StdLog"
Private Const xcsLibVersion = "1.0.0"
Private Const xcsFilePath = "LS_Log.nsf"    'ログDBのパス

'段落スタイル
Private xnrtpsMsg As NotesRichTextParagraphStyle     '通常ログ

'フォント定義
Private xnrtsDT As NotesRichTextStyle        'ログ時刻
Private xnrtsMsg As NotesRichTextStyle     '通常のメッセージ
Private xnrtsErr As NotesRichTextStyle       'エラーメッセージ

'ステータス管理
Private xbIsInit As Boolean         '初期化したか?
Private xbIsOpen As Boolean     'ログDBが取得済みか?

'カウンタ
Private xlMessage As Long    '通常ログ出力件数
Private xlError As Long           'エラーログ出力件数


◇ ライブラリの初期化

続いては、ライブラリの初期化です。ログ DB の取得を行い、取得できたら初期化できたことを xbIsInit に設定します。

Sub Initialize
   'ログDB取得
   Set xns = New NotesSession
   Set xndbCur = xns.CurrentDatabase
   Set xndbLog = xns.GetDatabase(xndbCur.Server, xcsFilePath, False)

   '取得成功なら初期化は OK
   If Not (xndbLog Is Nothing) Then
      xbIsInit = True
   End If

   '段落スタイル
   Call xInitParagraphStyle()
End Sub


◇ 段落スタイルの準備

初期化関数からコールしている xInitParagraphStyle は段落スタイルを設定準備する関数です。ログを出力する際に都度利用するので、あらかじめ準備しておき、いつでも利用できるようにします。

Private Function xInitParagraphStyle()
   '通常のメッセージ
   Set xnrtpsMsg = xns.CreateRichTextParagraphStyle()
   xnrtpsMsg.FirstLineLeftMargin = 1 * RULER_ONE_INCH
   xnrtpsMsg.LeftMargin = 6.5 * RULER_ONE_CENTIMETER
End Function

この設定を利用した段落は、1 行目の左マージンが 1 インチ(2.54cm)、2 行目以降が 6.5cm となります。これで、ログメッセージが長く右端で折り返しても日時の下には表示されません。


次回の予定

今回はライブラリの作成と初期化について紹介しました。次回以降はインターフェースとなる関数を順に紹介します。


前回 共通部品にチャレンジ 次回


2025/09/21

共通部品にチャレンジ:#2)LotusScript 実行ログ - フォームの作成

まずはログを表示するフォームを作成します。フォームのイメージは次の通りです。

現時点ではログ出力機能として最低限必要な項目のみ配置しています。その他項目は、関連機能追加のタイミングで追加することとします。なお、フォーム上の の部分は非表示の項目です。

作成に必要な情報を順に記載します。


フォーム情報

新規 DB を作成して、次の新規フォームを作成します。

フォーム名 1.LotusScript実行ログ
別名 fStdLog
ウィンドウタイトル @Text(LogStartTime; "D1T1S3") + " - " + Title

作成するフィールドは下記の通りです。このフォームは開発者やアプリの運用担当だけが見る前提にしていますので、理由がない限り ”編集可能” としています。


◇ 管理者([Admin] ロール)セクション

フォームにセクションを作成して、その中に管理用のフィールドを作成します。

項目 フィールド名 種類 補足
エラーフラグ IsError テキスト 編集可能 1 = エラーあり
通常ログ件数 LogMessageCount 数値 編集可能
エラー件数 LogErrorCount 数値 編集可能

セクションは [Admin] ロールを持っている人のみ表示させるよう非表示式を指定します。

!(
   @IsMember("[Admin]"; @UserRoles)
)

なお、セクションは初期状態を閉じておきましょう。これだけでロールを持たないユーザには、セクション丸ごと非表示にできます。


◇ ヘッダ情報

ログのタイトルや実行時間などの基本的な情報を表示するエリアです。次のフィールドを配置します。

項目 フィールド名 種類 補足 / 式
  Title テキスト 編集可能  
実行時間 LogStartTime 日付/時刻 編集可能  
LogEndTime 日付/時刻 編集可能  
エージェント AgentName テキスト 編集可能
AgentAlias テキスト 編集可能  複数値も可
IsOnServer チェックボックス 編集可能  
エラー LogError テキスト 編集可能  
LogErrorCount_D 数値 表示用の計算結果  LogErrorCount - 1
実行サマリー LogSummary テキスト 編集可能  

なお、エージェントの項目は、LotusScript がエージェントから実行された場合のみ出力されるように作成していきます。よって、AgentName に値があるときだけ表示させます。

!(AgentName != "")

エラーについては、エラーがあった場合だけの表示とします。

!(IsError != "")

ただし、エラー件数は、2 件以上の場合のみ表示とします。

!(LogErrorCount >= 2)


◇ 実行環境の情報

スクリプトを実行する DB とユーザの情報、ACL、実行環境を表示するエリアです。ACL と実行環境については、追って作成します。それに備えて、[基本情報]タブだけが存在するタブ形式の表にフィールドを配置します。

項目 フィールド名 種類 補足
DB 情報 DBTitle テキスト 編集可能  
Server テキスト 編集可能  
FilePath テキスト 編集可能  
 実行ユーザ名 UserName テキスト 編集可能  


◇ 実行ログ

フォームの下部には LotusScript 実行ログを記録するリッチテキストフィールドを配置します。

項目 フィールド名 種類 補足
 実行ログ Body リッチテキスト 編集可能  


前回 共通部品にチャレンジ 次回


2025/09/20

共通部品にチャレンジ:#1)LotusScript 実行ログ - 動作記録を一元管理

久しぶりに新しい連載を始めます。

とはいってもまったく新しいことを始めるのではなく、連載『作ってみよう』の派生です。『作ってみよう』は、アプリケーションを作ることを目的にしていますが、この連載では、アプリケーションで利用できる共通部品の作成に特化します。

最初のネタは、『LotusScript の実行ログ』の収集です。アプリ数が増えてくると各アプリが正常に動作しているか、エラーは発生していないか、日々巡回するのは手間がかかります。LotusScript の実行ログが一元管理されているだけでもアプリの運用監視が楽になりますね。

先日『LotusScript の実行確認と NotesLog クラス』で NotesLog クラスを使ったログの取得方法を紹介しました。このクラスを使用して、ログを指定したデータベースに出力できます。ただ、出力される項目は、時間、エージェント名、ユーザ名とログだけでかなりシンプルです。

これで一元管理はできるのですが、もう少し得られる情報が充実しているほうが、何かあったときの対応が楽になります。そこで、今回は自作のログ出力機能を作成したいと思います。


LotusScript 実行ログ

出力されるログのイメージはこんな感じです。上部に実行時間やエージェント名、エラーメッセージなどのヘッダ情報、中段にはユーザやアクセス権などの実行環境の情報、下部のリッチテキストにログを出力しています。

ログ部分は大量に出力されることを前提にリッチテキストにしています。せっかくのリッチテキストなので、エラーは赤の太字、日時は薄く表示してメリハリをつけ、見やすくしています。


◇ 経過時間の表示

また、ログ出力間の時間を測定し、閾値を越えると経過時間を表示する機能も作ります。簡易的にではありますが、レスポンスの遅い部分が調査できます。


◇ ACL 情報

LotusScript の実行者のアクセス権の情報を表示します。ACL の権限レベルだけでなく、ロールや文書の削除権限などの ACL のオプション情報も収集します。エラー発生時など権限の影響判定がしやすくなりますね。


◇ 実行環境

[実行環境]タブには、実行したクライアントのバージョンやプラットフォームの情報を表示します。環境に依存する問題の調査に利用できます。


作り方は次回以降

作成する設計要素は、ログを出力する DB のフォームとビュー、そして、ログを出力するためのスクリプトライブラリとなります。実アプリでログ機能を組み込む際には、スクリプトライブラリをアプリ内にコピペして、それを Use して利用するという流れとなります。

次回から順に機能の作成を進めます。


共通部品にチャレンジ 次回


2025/09/13

配列の次元数を取得する方法

今回は超個人的な備忘録です。

通常の業務アプリで必要となるシーンは思い浮かばないのですが、先日、汎用的なツールを作成しているときに必要となった処理です。それは、Variant 型変数に配列が入っていた時にその配列の次元数を確認する方法です。


配列であるかの確認

Variant 型 に配列が入っているかは、IsArray 関数で判定できます。

If IsArray(vUnknown) = True Then
   'vUnknown は配列
Else
   'vUnknown は配列ではない
End If


要素数の確認と次元

上記関数では、配列かどうかの判定はできますが、その次元数は判定できません。LotusScript にそれを取得する関数がないようなので、自作することにしました。

利用したのは UBound(LBound でも可)関数です。配列の要素数の最大値(最小値)を取得する関数なのですが、2 つ目の引数に次元を指定できます。

UBound ( arrayName [ , dimension ] )

例えば、3 次元配列の場合、以下のように記述すれば各次元の要素数の最大値が取得できます。

Dim aiArray(5, 3, 15) As Integer
Dim iMax1 As Integer
Dim iMax2 As Integer
Dim iMax3 As Integer
iMax1    = UBound(aiArray, 1)     ' 5
iMax2    = UBound(aiArray, 2)     ' 3
iMax3    = UBound(aiArray, 3)     ' 15


次元数の確認

UBound で存在しない次元数を指定した場合、エラーが発生します。これを利用して Variant 変数内の次元数を確認します。

次元数を返す関数のサンプルは次の通りです。

Function GetDimension(vaArray As Variant) As Integer
   Dim i As Integer
   Dim j As Integer

   On Error GoTo GeneralError

   For i = 1 To 8
      ' 存在しない次元を指定するとここでエラーになる
      j = UBound(vaArray, i)

      'エラーがないのその次元は存在
      GetDimension = i
   Next

ExitFunc:
   Exit Function

GeneralError:
   Resume ExitFunc
End Function


もし引数に配列でない値がセットされた場合には、初回の UBound でエラーが発生するので、0 が返されます。


2025/09/12

QueryAccessPrivileges の判定と演算子の活用

前回 の記事の中で ACL のオプションを取得する QueryAccessPrivileges メソッドを紹介しました。このメソッドの戻り値は、以下の値の組み合わせだと紹介しました。例えば、文書の作成ができて、削除のできる場合には、1 + 2 の 3 となります。これにパブリック文書の読者権限も持っていると 67 となります。

上記のように、戻り値で組み合わされた値が返ってきたとき、あなたならどのように判定しますか?

定数
1 DBACL_CREATE_DOCUMENTS
2 DBACL_DELETE_DOCUMENTS
4 DBACL_CREATE_PRIV_AGENTS
8 DBACL_CREATE_PRIV_FOLDERS_VIEWS
16 DBACL_CREATE_SHARED_FOLDERS_VIEWS
32 DBACL_CREATE_SCRIPT_AGENTS
64 DBACL_READ_PUBLIC_DOCUMENTS
128 DBACL_WRITE_PUBLIC_DOCUMENTS
256 DBACL_REPLICATE_COPY_DOCUMENTS


オプションの値の意味

話を単純化するために上から 4 つの場合を考えます。オプションの値は 1、2、4、8 で、取りうる値(組み合わせ)は 0 から 15 となります。列にオプションの値、行に取りうる値を整理すると次のようになります。

1 2 4 8
0 × × × ×
1 × × ×
2 × × ×
3 × ×
4 × × ×
5 × ×
6 × ×
7 ×
8 × × ×
9 × ×
10 × ×
11 ×
12 ××
13 ×
14 ×
15

これですぐわかりますね。オプションの値は 2 進数の各ビットの値を表すということになります。


判定方法

では、13 を例にどのビットが立っているのか考えてみます。大きいビットから考えて、

  1. 8 で割って 1 以上(〇)
  2. 8 で割った余り 5 を 4 で割って 1 以上(〇)
  3. 4 で割った余り 1 を 2 で割って 1 未満(×)
  4. 2 で割った余りが 1(〇)

というよな判定となります。

これを逐一 If 文で書くと結構な分量になります。また、QueryAccessPrivileges のように 256( = 9 ビット)までとなるととんでもない分量になることが想像できます。

そこで、プログラミングらしく、ループを使って効率的に判定する方法を考えてみましょう。

Sub Initialize
   Dim iBit As Integer
   Dim iSrc As Integer    'サンプル地
   Dim iOpt As Integer   'オプションの値

   iSrc = 13

   '上のビットから順に処理
   For iBit = 3 To 0 Step -1
      'ビットの値を算出
      iOpt = 2 ^ iBit

      'ビットが立っているか判定
      If iSrc / iOpt >= 1 Then
         MsgBox CStr(iOpt) & " = 〇"
      Else
         MsgBox CStr(iOpt) & " = ×"
      End If

      'ビットの値の余りを算出
      iSrc = iSrc Mod iOpt
   Next
End Sub

べき乗の演算子(^)と剰余を求める命令(mod)を使い、上のビットから演算を進めることで、ループを効率的に活用しています。

なお、If 文の判定では、判定方法に記載した通り割り算を使用しましたが、以下のように書き換えることができます。

      If iSrc >= iOpt Then

割り算した結果を比較して判定するより、整数値を比較するだけの方が明らかに演算コストが安いですよね。


論理演算の動作

もっと簡単に判別する方法はないでしょうか? 実はあるんです。

それは、論理演算子 And を使用する方法です。If 文で複数の条件を記述する際に利用するあの And のことです。

      If a = b And b = c Then

And 演算子は上記のような使い方のほかに 2 つの値のビットを比較し、その結果を返す機能があります(上記判定もその一部)。事例に挙げた 13 の場合と 3 の And の結果は次のようになります。

   13 And 8 = 1101 And 1000 = 1000 = 8
   3 And 8 = 0011 And 1000 = 0000 = 0

And 一つあればそのビットが立っているか判定できることがわかります。


論理演算の活用

最初の表の定数は 1, 2, 4, 8, 16 … と各ビットの値が定数化されています。この定数と And とを活用すると保持しているオプションが ”ワンパン” で判定できます。

例えば『個人フォルダ/ビューの作成』を持っているか判定する場合、次のように記述します(iOpt に QueryAccessPrivileges の戻り値が入っている前提)。

   If (iOpt And DBACL_CREATE_PRIV_FOLDERS_VIEWS) > 0 Then


まとめ

今回は、QueryAccessPrivileges の戻り値を題材に論理演算子の活用方法についてまとめました。

ご存じの通り、コンピュータは 2 進数で動作しています。それを活用した演算子や言語仕様が各所にちりばめられています。10 進数で姓つしている私たちには気が付きにくいのですが、うまく活用することで、超お得になることがあります。

デザイナーヘルプやサンプルを見て、2 進数っぽいものが出てきたら調べてみましょう。お宝が発見できるかもしれませんよ。


2025/09/11

アクセス権限とロールの取得 - LotusScript

前々回 は DB に対してアクセスレベルと文書の削除権限などのオプション設定を取得する関数である @UserAccess、前回 はロールを取得する @UserRoles を紹介しました。同様の情報は LotusScript  でも取得可能です。

使用するのは NotesDatabase クラスのメソッドとなります。順に確認しましょう。


アクセスレベルの取得

データベースに対する現在のアクセスレベルを返します。構文は次の通りです。

level% = notesDatabase.QueryAccess( name$ )

引数は1つです。

1 name$ 文字列 ユーザ、グループ、または、サーバ名

@UserAccess との使い方の違いは、

  • 調査する DB が引数ではなく、DB オブジェクトを取得してそのメソッドをコールする
  • 現在のユーザだけでなく、調査する名前を引数で指定する
  • 引数にはユーザだけでなく、グループやサーバ名を指定できる

点となります。

また、戻り値についても注意が必要です。@UserAccess と同じく 0(なし)~ 6(管理者)を返すのですが、型は ”文字列” ではなく Integer 型となる点にも注意してください。


オプションの取得

文書の作成や削除権限など ACL のオプション設定を取得するには、QueryAccessPrivileges メソッドを利用します。

privileges& = notesDatabase.QueryAccessPrivileges( name$ )

使い方や引数は、QueryAccess メソッドと同じでです。

戻り値は数値なのですが、少し特殊で、次の値の組み合わせで返します。これは複数のオプションが指定されることへの対処ですね。判定時には、値と定数のどちらでも使用できます。

定数
1 DBACL_CREATE_DOCUMENTS
2 DBACL_DELETE_DOCUMENTS
4 DBACL_CREATE_PRIV_AGENTS
8 DBACL_CREATE_PRIV_FOLDERS_VIEWS
16 DBACL_CREATE_SHARED_FOLDERS_VIEWS
32 DBACL_CREATE_SCRIPT_AGENTS
64 DBACL_READ_PUBLIC_DOCUMENTS
128 DBACL_WRITE_PUBLIC_DOCUMENTS
256 DBACL_REPLICATE_COPY_DOCUMENTS

定数名を見ればどのオプションかはすぐ分かるので、説明は割愛しています。

@UserAccess との違いは『文書を複製またはコピー』オプションも含めて処理してくれる点です。


ロールの取得

ロールを取得するには、QueryAccessRoles メソッドを利用します。使い方や引数は、上記メソッドと同じです。

roles = notesDatabase.QueryAccessRoles( name$ )

戻り値は String 型の配列となります。


名前の指定方法

引数はすべてのメソッドで共通ですが、指定方法には少しだけ注意が必要です。ユーザ名を指定する場合、階層付きでつける必要があります。


指定するユーザ名
× User01 Notes
User01 Notes/Domino
CN=User01 Notes/O=Domino


まとめ

今回は、LotusScript でアクセス権限やオプション、ロールを取得する方法をまとめました。これら機能は @UserAccess や @UserRoles に比べ後発の機能なので、使用がスッキリまとまっていますね。


2025/09/09

ロールの取得 - @UserRoles

前回は接続ユーザのアクセスレベルや文書削除権限などのオプション設定を取得する関数 @UserAccess を紹介しました。今回は同じく ACL 設定からロールを取得する @UserRoles を紹介します。


機能と構文

 @UserRoles は、現在のユーザが持つロールを取得することができます。構文次の通りなのですが、引数がありませんので、構文というほどのものではありませんね...

@UserRoles

戻り値は文字列リストで、現在のユーザが持つロールが列挙されます。また、戻り値内のロール名は [ ](角括弧)で囲まれた文字列となります。


利用例

ロールの利用例として一般的なのは、アクションボタンの非表示だと思います。上記 ACL 設定を例にすると、[Approver] ロールを持ったユーザのみ[承認]ボタンを表示するというものです。具体的には次のように記述します。


!(
   @IsMember("[Approver]"; @UserRoles)
)

@UserRole の戻り値はリスト値となるので、それを前提とした式の記述が必要です。上記式では @IsMember を利用してリスト値内に存在するかを確認しています。

アクションボタンの非表示やリスト値の演算に関しては以下の記事も参考にしてください。


2025/09/08

アクセスレベル(ACL)の取得 - @UserAccess

ACL の設定で文書を作成する権限がないのに[新規作成]ボタンが表示されるのはおかしいとエンドユーザやお客様から指摘されたことはありませんか? こんな時に利用できるのが @UserAccess という関数です。今回はこの関数の動作についてまとめます。


機能と構文

 @UserAccess は、引数で指定したデータベースに対して、現在のユーザのアクセスレベルを含む、アクセス情報を詳細に確認することができます。構文は次の通りです。

@UserAccess( server :file ; [ accessPrivilege ] )

引数は次の通りです。

1 server  文字列 サーバ名
file  文字列 データベースのファイルパス
2 accessPrivilege キーワード 省略可能
特定のアクセス情報を指定して取得する場合に利用

最初の引数は、サーバ名とファイル名をリストで指定するタイプで、@DbLookup など他の関数と同様です。通常は、自分自身の DB を調査することになるので @DbName を指定することになりますね。


戻り値(キーワードなし)

まずは、キーワードを省略した場合の戻り値の確認です。

@UserAccess(@DbName)

この式をフィールド(複数値可)のデフォルト式にセットします。作成者ユーザでテストした結果は次のようになります。

最初がアクセスレベルで、0(なし)~ 6(管理者)を表します。それ以降は各オプションの設定(1 でチェック)となります。非常にわかりやすいのですが、いくつか注意点があります。

1つ目は、戻り値は文字列リストである(数字だが ”数値” ではない)ことです。この結果を使った非表示式を記述するときなどでは、混乱しがちとなりますので注意してください。

2つ目は、オプションに『文書を複製またはコピー』が含まれない点です。このオプションは、@UserAccess がリリースされて以降に追加されました。既存のアプリに影響が出ないよう配慮されているからです。その代わりとして、省略可能な引数 accessPrivilege が追加され、そのオプションを取得できるように拡張されています。

互換性を保ちつつ、機能追加も行われた結果ということですね。


引数 accessPrivilege の使い方

この引数を使うと特定の権限だけの結果を得ることができます。例えば、先の『文書を複製またはコピー』の設定を取得するのであれば、次のように指定します。『文書を複製またはコピー』にチェックがあれば ”1”、なければ ”0” を返します。

@UserAccess(@DbName; [REPLICATEORCOPYDOCUMENTS])

指定できるキーワードは、次の通りです。

[ACCESSLEVEL] アクセスレベル
[CREATEDOCUMENTS] 文書の作成
[DELETEDOCUMENTS] 文書の削除
[CREATEPERSONALAGENTS] 個人エージェントの作成
[CREATEPERSONALFOLDERSANDVIEWS] 個人フォルダ/ビューの作成
[CREATELOTUSSCRIPTJAVAAGENTS] LotusScript/Javaエージェントの作成
[CREATESHAREDFOLDERSANDVIEWS] 共有フォルダ/ビューの作成
[READPUBLICDOCUMENTS] パブリック文書[読者]
[WRITEPUBLICDOCUMENTS] パブリック文書[作成者]
[REPLICATEORCOPYDOCUMENTS] 文書を複製またはコピー

また、キーワードは :(コロン)を使って複数指定でき、戻り値はその要素だけを含んだリスト値となります。


まとめ

今回は @UserAccess 関数を紹介しました。これを利用すれば、ACL で設定したアクセスレベルやオプションを判定できます。例えば、この記事の最初に記載した『文書を作成する権限がないユーザには[新規作成]ボタンを表示しない』式は次の通りとなります。

!(
   @UserAccess(@DbName; [CreateDocuments])="1"
)

ここまで詳細な非表示の制御は、個人的には費用対効果が低いと考えており、設定していません。ただ、「できない」と「できるけどしない」は大きな違いだと思います。