Ben Spead · Mar 31, 2017 go to post

Steve,

Here is some sample code that should help get you going in the right direction.  NOTE - the byRef LD argument is a handle for the connection to the LDAP server and it needs to be cleaned up when you're done if you're going to fetch any attributes.  

(sorry for the messed up indentation)

 /// Authenticates against the configured domain, with username/password, passing a resulting a status ByRef and a returning success/failure value
ClassMethod Authenticate(username As %String, password As %String, ByRef Status As %Status, ByRef LD As %Integer) As %Boolean
{
Set Status=$$$OK, ret=0
If ('$data(username))||('$data(password)) 
    Set Status=$$$ERROR($$$GeneralError,"Both fields are required") 
    Quit 0
}

Set sc=$$$OK
Try {
//Connect to the LDAP server
Set LDAPServer="myldapserver.mydomain.com"
Set sc=$$$OK
Set LD=##class(%SYS.LDAP).Init(LDAPServer)
If LD=0 {
        Set LDAPStatus=##class(%SYS.LDAP).GetLastError()
        Set sc=$$$ERROR($$$GeneralError,"LDAP Init Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
Else {
    //Authenticate the passed in user by using the Binds command 
    Set Domain=..GetDomain()
    If ($$$isWINDOWS) {
        Set LDAPStatus=##Class(%SYS.LDAP).StartTLSs(LD)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP StartTLSs Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    Else {
        Set LDAPStatus=##Class(%SYS.LDAP).Binds(LD,"",$lb(username,Domain,password),$$$LDAPAUTHNEGOTIATE)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP Binds Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    } 
}
ElseIf ($$$isUNIX) {
    Set cert = ..GetCert()
    Set LDAPStatus=##Class(%SYS.LDAP).SetOption(LD,$$$LDAPOPTXTLSCACERTFILE,cert)
    If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP SetOption Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
        Do ..RotateOnFailure(sc)
Else {
        Set LDAPStatus=##Class(%SYS.LDAP).StartTLSs(LD)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP StartTLSs Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    }
}
If LDAPStatus=$$$LDAPSUCCESS {
    Set LDAPStatus=##Class(%SYS.LDAP).SimpleBinds(LD,username_"@"_Domain,password)
    If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP SimpleBinds Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    }
}
Else {
    Set LDAPStatus=$$$LDAPAUTHMETHODNOTSUPPORTED
}
If (LDAPStatus'=$$$LDAPSUCCESS)&&($$$ISOK(sc)) {
    Set sc=$$$ERROR($$$GeneralError,"LDAP API Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
}
} 
Catch err {
    Set sc = $$$ERROR($$$GeneralError,err.Data) 
}
If $$$ISOK(sc) {
     Set ret = 1
Else {
    Set Status = sc 
}

Quit ret
}
Ben Spead · Mar 30, 2017 go to post

I certainly hope that the mystery parties who have been moderating that site are reaching out to Google in order to get it reinstated.  There was certainly a lot of valuable information on that site!

Ben Spead · Mar 24, 2017 go to post

You can use $system.OBJ.Load() or LoadDIr() to load source from disk.

Ben Spead · Mar 23, 2017 go to post

Personally, I would do this via Source Control and not via Studio.  The approach to this will depend on your source control structures, etc, but the easiest way to handle this for me would be:

1) Make sure that everything in my package was checked into my branch, e.g. /MyApp/cls/MyFirstPackage/...

2) Since my source tree is structured according to package names, I would copy /MyApp/cls/MyFirstPackage/... to /MyApp/cls/MySecondPackage/... 

3) Check in /MyApp/cls/MySecondPackage/... into source control

4) Check out /MyApp/cls/MySecondPackage/... 

5) Do a Find & Replace in /MyApp/cls/MySecondPackage/... to replace all instances of "MyFirstPackage" with "MySecondPackage"

6) Diff /MyApp/cls/MySecondPackage/...  and make sure all replacements are desired

7) Check in /MyApp/cls/MySecondPackage/... 

8) Run my build routine to pull all of /MyApp/cls/MySecondPackage/...  into my namespace and Compile it (or just use $system.OBJ.LoadDir() if you don't already have a build routine)

Voila!  Package is duplicated and all checked into source control ready for further changes :) The above process should only take a couple of minutes.

Ben Spead · Mar 16, 2017 go to post

The lock controls the source control hooks, so anything relying on the hooks should prevent changes to items under source control.  Parts of the Ensemble Management Portal and the DeepSee portal tie in the hooks for that namespace, so I can see there being a possible interplay there.  I have never used the "Deploy Production Changes" utility so I can't say for certain if the source control lock is coming into play there.

You should work through this with Managed Services to find a resolution. 

Ben Spead · Mar 16, 2017 go to post

No - CCR is not a 'released product'.  But there are implementation sites partnering with InterSystems that use it.  

Ben Spead · Mar 15, 2017 go to post

Scott,

See the Documatic for the following methods in %Studio.SourceControl.ISC:

classmethod Lock(Admin As %Boolean = 0) as %Status

Lock the source control hooks for this instance.

The default setting will be "Locked". Passing a '1' for the Admin parameter will set the instance to AdminLocked.

See Locked for more details.

classmethod Locked() as %String

Returns value that shows whether or not this instance is "Locked"

Return values are:

  • "": Instance has never been Locked or Unlocked (default)
  • 0: Instance is Unlocked
  • 1: Instance is Locked
  • 2: Instance is AdminLocked

When the instance is Locked or AdminLocked, no changes can be made via Studio. It is possible to change from Locked to NotLocked via different UIs. When an instance is AdminLocked it should only be possible to unlock it via the Unlock method.

classmethod Unlock() as %Status

Unlock the source control hooks for this instance.

Ben Spead · Mar 10, 2017 go to post

Andreas - should this be cross-posted on the InterSystems Compatibility blog?

http://blog.intersystems.com/compatibility/

My guess is that there may be some people who follow that who might miss this significant announcement on the Developer Community.  I know I missed this when it was originally posted.

Ben Spead · Mar 10, 2017 go to post

You should never do that.  That is a stripped down version of apache which should only be used for the Management Portal.  You need to install your own full web server

Ben Spead · Mar 7, 2017 go to post

Thanks Tim!!  Very helpful.

One question /comment - your approach doesn't allow for case insensitivity of the http(s)/ftp prefix.  I would prefer to set the case insensitivity flag for the whole pattern.

According to the ICU documentation (http://userguide.icu-project.org/strings/regexp#TOC-Flag-Options):  

[quote]

(?ismwx-ismwx) Flag settings. Change the flag settings. Changes apply to the portion of the pattern following the setting. For example, (?i) changes to a case insensitive match.

[/quote]

So I was able to make it work as follows:

set matcher=##class(%Regex.Matcher).%New("(?i)(\b(https?|ftp)://[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|])",string)
set string = matcher.ReplaceAll("<a href='$1' target='_blank'>$1</a>")
 

Thanks for the tips and pointing me in the right direction!

Ben Spead · Feb 6, 2017 go to post

Sergey - I also appreciate the point about the "component" approach (as we're using 1.x + Angular Material).  If you have any good references or tutorials on that approach (and/or contrasting with the 'typical' approach to do Angular 1.x), please post them :)

Ben Spead · Jan 23, 2017 go to post

Gaolai,

You need leading whitespace on any line of a routine which is not a line tag.  Try putting a space or Tab on your 2nd and 3rd lines.

Also, "Hello there!" isn't a valid COS command.  Try using:

   Write "Hello There!"

Ben Spead · Jan 10, 2017 go to post

If we change the unanswered query to only include questions with 'true' answers selected, do we expect everyone to be good enough citizens to go back and select true answers once they are provided?  Would admins be able to mark true answers if the author abandons the thread?

Ben Spead · Dec 22, 2016 go to post

Removed as requested (although I personally think that the screenshot makes people more likely to take a look at your code rather than less likely).

Ben Spead · Dec 12, 2016 go to post

For debugging or programmatic purposes?  If debugging / interactive you can just zwrite the variable to see the properties.

Ben Spead · Nov 10, 2016 go to post

Michael - thanks for the article.  It would be really helpful if you could add a paragraph at the top explaining what the Ensemble scheduler is and what it's main use-cases are so that people can tell quickly whether or not this is something which they would want to learn more about.  Perhaps as an Intro?

Ben Spead · Nov 10, 2016 go to post

I think that may be a custom routine.  I don't recognize it as a Caché-supplied resource. 

Ben Spead · Nov 10, 2016 go to post

My guess is that you are passing data somewhere as a string (because that is around the string limit). You need to use streams instead to store the uploaded file.

Ben Spead · Nov 1, 2016 go to post

Assuming you are a supported customer, you can download this from the Distributions page in the WRC application.

Ben Spead · Oct 31, 2016 go to post

This is not a Caché utility - it must be supplied by your application partner.  Also, the AP must be storing their own users at the application level because if they were using Caché users there would be no way to create a utility that shows Caché users' passwords (see Patrick's answer below).

I suggest you reach out to your application partner with this question (or if it is an inhouse development, speak with the development team)

Ben Spead · Oct 27, 2016 go to post

Sorry - I missed that.

Getting the "When" is easy - there is a timestamp in the header of the generated .INT code showing when the source was last compiled.  E.g:

 ;Sample.Address.1
 ;(C)InterSystems, generated for class Sample.Address. Do NOT edit. 10/27/2016 09:12:38AM
 ;;7A2F686C;Sample.Address
 ;
However the "Who" might prove to be more challenging. You might be able to accomplish this with a Method Generator that records the $Username and timestamp for access via a method or parameter?  See http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

Ben Spead · Oct 27, 2016 go to post

You can add logic in %OnAfterSave() for your object which will grab the object ID, $Username and the timestamp and tuck them away in an auditing table somewhere.  Alternatively you could add LastChangedBy and LastChangedTimestamp properties to your object and then populate them inside of %OnAddToSaveSet() (this is probably the most straightforward way to do it).

Hope that helps!