Hi Yoav

What I would look at is creating a Caché class method that does most of the work

In %SYS you can do things like

List all Users

&sql(declare c1 cursor for
select ID into :xID from Security.Users

And to open the user object

set oUser=##class(Security.Users).%OpenId(<the_id>)
And then the properties you need to update for two factor are oUser.PhoneProvider and oUser.PhoneNumber

= =

Access management would be by roles - again this is available from oUser.Roles
and the related class is Security.Roles

= =

Don't know about Captcha - but this would be client side - not serer side

Hope this helps

Hi Anne

Looks like we are on the same journey - have a look here on what I have so far

= =

I have no real answer to the logon issue - I think the "correct" solution is for Intersystems to provide a restful logon service to provide this functionality that can be accessed without being already logged on.

One possibility that I can think of that *may* work (have not tried it *yet*) ....
create a separate CSP web site that has no restrictions on logging on - with a single restful service "logon"  - in can be in the same namespace but with a different dispatch class.

The COS then performs a $System.Security.Login("username", "password") 
and returns success or fail - and sets up the session token

I can see that there may be issues with CORS - but I don't understand this topic yet :}

= =

As an aside....
I have been working with Caché for (too) may years and their security model/features is hidden away, difficult and subject to change.
I can understand this - they need to protect their commercial interests - eg it is technically possible for a minimal license (5 users) to support 1,000's of end user clients - clearly not commercially sensible.


Hey Kev

Try this

set x1="""this is a quoted string with a ' in it"""

set x={"fred":"123", "TheQuotedString":(x1)}

write x.%ToJSON()
{"fred":"123","TheQuotedString":"\"this is a quoted string with a ' in it\""}

The %ToJSON() does the escaping for you - or do you need something else?


Hi Kev

Hope you are keeping well

Have you tried

write $System.OBJ.UnCompile("*") from terminal? - replace the "*" with more specific wild card

write $System.OBJ.Delete("class name") 


write $System.OBJ.DeletePackage("package name")

I had similar issues -but difficult to pin down


Hi Sabarinathan

I use pdfPrintCmd - see http://www.verypdf.com/app/pdf-print-cmd/index.html

it's not free but I have had no issues with it over many years of use

The idea is:
a. Write out the pdf to a directory
b. set xResult=$zf(-1, "print command exe")

The great advantage is that it has command line options that control margins, double sided etc etc

Also it can be run in the background - this is very useful when doing batches of pdf where creating the pdf using FOP can take several seconds - the idea is
a. scan the data via SQL
b. create the pdf
c. use printCmd to send to a printer
To give you an idea of it working I have a client that produces around 50 multi page passport a day - the printing takes around 1 hour - it's set going as a Cache background job and the printer just chugs away.


Hi Kyle

Thanks for your excellent comment

I agree - sort of....

Bit it's a balance (as always) between loading buffers - it may be the case that there is an occasional need to just grab the dates - but if it's only a 10% (say) need whereas the 90% need is to display/process the header and the lines together then, for me, the 90% need should win out.

Also if the dates (or whatever) are indexed then a selection on a date range (say) will only select the required rows from the index.

= =

But as I said before - it depends on the size of the system - my clients have modest needs (maybe 3 million rows max) and with a 64Gb machine all/most of the blocks are in memory anyway smiley


But thanks for the thoughts - I will certainly start looking at one-many with a cascade delete