David Hockenbroch · Jul 29, 2022 go to post

You can probably make that work, but why not put the method in a %CSP.REST class to start with and have the CSP page call it? That seems more in line with the way those things are meant to be used.

David Hockenbroch · Jul 20, 2022 go to post

On whichever answers you want to mark as an answer, click the check mark next to the reply button. That should mark that reply as an answer.

David Hockenbroch · Jul 20, 2022 go to post

Postman is a pretty standard tool for this. Even the free version gives you everything you need to get started, and if you end up collaborating with other groups on your API, or if your end users want to do some testing, it's easy to get them and share a collection of requests.

David Hockenbroch · Jul 18, 2022 go to post

I think what you're looking for might be setting the isolation level to read committed. This will make the process wait for the in-progress changes have been committed, though you'll still want to make sure you handle SQLCODE -114 somehow, too. That's the code you get back if there's a timeout waiting for the lock. You should be able to set that using:

%SYSTEM.SQL.Util.SetOption("IsolationMode",1,.oldval)

If you do that before your query, the rest of the process will run at that isolation level.

You can use that same method to set the LockTimeout too, by the way. Default is 10 seconds.

David Hockenbroch · Jul 18, 2022 go to post

In your post, you say "Result is nothing is returned and %SQLCODE is 0". I just want to make sure this isn't just a misunderstanding. If the SQLCODE is 0, that would mean that there is a result returned. When the query executes successfully and nothing is returned, the SQLCODE is 100.

David Hockenbroch · Jul 18, 2022 go to post

The error seems to occur when it's trying to access the log file. Under you advanced settings, have you checked where it's trying to find or create your log file and made sure it's valid?

David Hockenbroch · Jul 7, 2022 go to post

$EXTRACT(input,$FIND(input,"(")-1,*)

$EXTRACT(string,index1,index2) creates a substring out of the initial string from index1 to index2. $FIND finds the first occurrence of ( in the string, so that -1 includes the ( itself. When you're using extract, * is shorthand of the last character of the string.

David Hockenbroch · Jun 22, 2022 go to post

Ideally, that would be the case, but some of these aren't apps we've written and are forcing to log in with a safe user account. They're 3rd-party apps that our users are logging into using their usual credentials to create an ODBC connection. Most of them are reporting tools, but a few are also capable of running queries other than selects.

I think what we'd like to be able to do is determine roles similarly to how you can set up application roles so that the user gets those roles when they log in, we set permissions based on the program being used. Can we do that somehow in ZSTART?

David Hockenbroch · May 31, 2022 go to post

It sounds to me like there's an issue with the design there. If the field can be duplicated, why is it marked as unique at all?

David Hockenbroch · May 31, 2022 go to post

Rochdi, I'd get rid of:

Set Line = File.Read(1000)
While (File.Read(1000)'="") {S mystring=mystring_File.Read(1000)
} 

And then after your set Httprequest = ##class(%Net.HttpRequest).%New(), use:

set sc = Httprequest.EntityBody.CopyFromAndSave(File)

Then you can check sc to see if you got any errors doing that.

David Hockenbroch · May 31, 2022 go to post

Your tResult will have a property called %SQLCODE that gets set when the query is run. If %SQLCODE = 100, that means that the query ran successfully but returned no results or that you've reached the end of the result set. If %SQLCODE = 0, you have some results. If %SQLCODE is less than zero, that's an error code.

if tResult.%SQLCODE = 100{

//whatever you want to do for no results here

}

David Hockenbroch · May 27, 2022 go to post

If you're encoding your data before sending it, you have to specify how it was encoded in a content encoding header so that the server you're sending data to knows how to decode it.

I think it's more likely, though, that it's an issue with your content type. Where you're setting it to "text/plain", if it's supposed to be json, you might try setting it to "application/json" instead.

David Hockenbroch · May 27, 2022 go to post

How certain are you that the server you're sending the request to accepts a content type of "text/plain"? Having that wrong, or using the wrong encoding are probably the most common causes of a 415 error.

David Hockenbroch · May 18, 2022 go to post

If the file isn't accessible to link to directly, you may want to look into extending the %CSP.StreamServer class and linking to that. At a bare minimum, you'll want to override the OnPage and OnPreHTTP methods:

ClassMethod OnPage() As %Status
{
set myfile = ##class(%File).%New("/path/to/file")
do myfile.Open("S")
do myfile.OutputToDevice()
quit $$$OK
}

ClassMethod OnPreHTTP() As %Boolean [ Language = cache ]
{
do %response.SetHeader("Content-Disposition","attachment;filename=""filename""")
quit 1
}

Of course using your own file name and the path to the file. That's the local computer file path, not a URL. You also should set the content type appropriately using set %response.ContentType = "text/csv" or whatever the MIME type of the file is so that the browser can identify it correctly.

Unless you want to have to write another %CSP.StreamServer for every file, you'll have to pass the name of the filepath as an argument. So that would look more like:

ClassMethod OnPage() As %Status
{
set myfile = ##class(%File).%New(%request.Get("filepath"))
do myfile.Open("S")
do myfile.OutputToDevice()
quit $$$OK
}

ClassMethod OnPreHTTP() As %Boolean [ Language = cache ]
{
set filepath = %request.Get("filepath")
set %response.ContentType = "text/csv" //or whatever the appropriate MIME type is
do %response.SetHeader("Content-Disposition","attachment;filename="""_$P(filepath,"/",*)_"""")
quit 1
}

Then you could link to it as whatever the path to your stream server is with ?filepath=/path/to/file on the end.

If you take that approach, though, do some validation on the filepath and make sure it can ONLY go to the folder you want! Or, only pass the filename as a parameter to the page, and hard-code the folder in those methods.

David Hockenbroch · May 18, 2022 go to post

It looks like in your curl you have the Accept header as */*, but in your HttpRequest object, you're setting it to "application/json". Does that make a difference?

David Hockenbroch · May 17, 2022 go to post

Even in the global masters rewards where they have an RPi available with IRIS preinstalled, it's running on Ubuntu, not Raspbian, so that part didn't surprise me.

As python becomes more widely adopted in IRIS and word gets out about it, I won't be surprised if some of the RPi community shows up with some pretty cool projects using IRIS Community since a lot of them are python developers. InterSystems tends to lean into health care as the main thing, but there you've got a device that you can connect all kinds of sensors and gizmos to that may lend themselves well to other fields. Let's not be hasty dismissing it because it can't run an entire hospital.

David Hockenbroch · May 16, 2022 go to post

In addition to the methods already mentioned, a lot of the %Library classes also have a class method called IsValid that you can use. For instance if ##class(%Numeric).IsValid(n) returns a 1, then n is a valid numeric value.

David Hockenbroch · May 12, 2022 go to post

Are you sure you copied in the right SQL queries in your post? The ones you've included both try to update the EmailOptIn column to 0 where it's already set to 1, not where it's null. It seems to be they should be something more like "update Person set EmailOptIn = 0 where EmailOptIn is null".

David Hockenbroch · May 9, 2022 go to post

Are you just trying to get the json contained in a character stream into a string a vice versa? If so, just read and write to and from the stream:

set json = ""
while 'stream.AtEnd
{
    set json = json_stream.Read()
}

That should get you the contents of the stream into a string.

do stream.Write(json)

That should write the json to a stream.

Or is that not what you're trying to do?

David Hockenbroch · May 5, 2022 go to post

Methods that return a %Status don't automatically throw an exception. You have to check if the %Status is an error and throw it yourself. After your SendFormDataURL call, you might want to add the following and see if that gives you any more information:

if $$$ISERR(st) {
  throw ##class(%Exception.StatusException).CreateFromStatus(st)
}

However given that the HTTP status of the response is a 500 (an internal server error) there may also be a problem on that end.

David Hockenbroch · Apr 27, 2022 go to post

There isn't a hard limit on the number of tasks, but you may run into licensing issues. As you set them up, you choose the user they run as, so if that user has too many connections going at once, or if they're run as more different users than you have licenses for, there could be an issue.

David Hockenbroch · Apr 5, 2022 go to post

I'm not sure your question is clear, but creating a new instance of that class in ObjectScript should be as simple as:

set myDTL = ##class(Ens.DataTransformDTL).%New()
David Hockenbroch · Apr 1, 2022 go to post

Once you know the pid, try:

set process = ##class(%SYS.ProcessQuery).%OpenId(pid)

Then check process.Routine, or process.CurrentLineAndRoutine.

David Hockenbroch · Feb 18, 2022 go to post

Here's how I've been doing this:

//Read in content from the HttpRequest
set req = %request.Content.Read()

//Convert content from JSON to a dynamic object
set reqObj = {}.%FromJSON(req)

//Access data from within the new dynamic object
set userName = reqObj.%Get("UserName")
David Hockenbroch · Feb 11, 2022 go to post

Eduard, can't the MAXSTRING one also mean that you've exceeded a specified MAXLEN parameter on a string? Like if I have a Property LastName As %String (MAXLEN = 30) and you try to save the object with a 50 character last name, doesn't that also give a "MAXSTRING" error?