How do I set up the application folder and it's sub-folders to be inaccessible to casual browsing, and only allow the application to access them?

Depending on your goal, there are different approaches available. Do you want user to see images only after logging into the application (so a general control on resources) or do you want individual access (only some users can see a specified image)?

If it's a first one, go to the web application configuration page and set Serve Files to Use InterSystems Security. In that case if the user has permissions to view a csp/cls page in this application then allow them to view a static file, if they do not have permissions to view a csp/cls page then return a 404 page not found page.

For a second case, use REST Broker to serve files and implement arbitrary checks in the broker.

That depends on the precision you need.

1. If you need just close enough you can do this:

  • Check how much time, on avarage BS takes to run. Let's say X seconds
  • Set Call Interval on your BS to 86400-X
  • Start BS at 10:00 AM
  • Assuming average runtime stays constant it should work well enough

2. If you need to run your BS at exactly at 10:00 AM use this task to achieve that.

Something like this:

#dim results As EnsLib.LDAP.Message.Results
for i=1:1:results.Results.Count() {
	#dim result As EnsLib.LDAP.Message.Result
	set result = results.Results.GetAt(i)
	write "DN: ", result.DN, !
	write "Attributes: ", !
	for j=1:1:result.Attributes.Count() {
		#dim atribute As EnsLib.LDAP.Message.Attribute
		set atribute = result.Attributes.GetAt(j)
		write $$$FormatText("  - Name: %1, Result: %2, Value: %3", atribute.Name, atribute.Result, atribute.Value), !
	}
}

I'll start from the simplier one:

and also the use or  DISPLAYLIST &  VALUELIST does this brings any advantage vs defining a standard property (eg.fast access!), so instead of have to do Valuetist "H" and Dispay "Hot" why just a standard property as string containing "Hot"?

More effective storage. If you can replace Cold with 1, Medium with 2 and Hot with 3 you can save some space. Another reason is that VALUELIST turns a string into a enum, which changes the logic considerably.

Issue looks specific to dynamic objects:

USER>w $zv
IRIS for Windows (x86-64) 2022.1 (Build 209U) Tue May 31 2022 12:16:40 EDT
USER>set obj={"Id":"myId"} 
USER>write $property(obj,"Id")
myId
USER>write $method(obj,"IdGet")
 
WRITE $METHOD(obj,"IdGet")
^
<METHOD DOES NOT EXIST> *IdGet,%Library.DynamicObject

USER>set obj = ##class(User.A).%New()
USER>write $property(obj,"Id")
myId
USER>write $method(obj,"IdGet")
myId

Great find, Tani!

You can also use the same trick to remove roles temporarily (for example if you need to execute untrusted code):

Class User.Role
{

/// do ##class(User.Role).Test()
ClassMethod Test()
{
    do ..SecurityContext("Test before")
    do
    . new $roles
    . do ##class(%SYSTEM.Security).Login("UnknownUser") // has no roles
    . do ..Untrusted()

    do ..SecurityContext("Test after")
}

ClassMethod Untrusted()
{
    do ..SecurityContext("Untrusted")
}

ClassMethod SecurityContext(context)
{
    w "Context: ", context, !
    w "Roles: ", $roles, !
    w "User: ", $username, !, !
}

}

Produces this output:

Context: Test before
Roles: %All
User: _SYSTEM
 
Context: Untrusted
Roles:
User: UnknownUser
 
Context: Test after
Roles: %All
User: _SYSTEM