Push to Specific User - delphi

Writing in Delphi 10 Seattle, targeting the 'pusher' as Windows, and the receiver as iOs (for now). The aim is to be able to push a message to a specific user without relying on broadcast and client side filtering.
I've managed to achieve the following so far:
1. Send a broadcast push to my iOS app
2. Login as a user on my iOS app
3. Create a pointer in my Installation record for User -> _User
That's as far as I can get in Delphi. From what I understand, I have to update the Installation record on login to reflect the installations logged in user.
I cannot find out how to do that in Delphi's Parse/BAAS objects. What seems to be missing is that I can't get the logged in users Installation ID. I assume if I could I could then update that via the TBackendStorage Class.
Any help would be appreciated.
I've cross posted this question to Embarcadero forums and community site.

To retrieve the User Object Id
var
ACreatedObject: TBackendEntityValue; // REST.Backend.MetaTypes
begin
BackendUsers.Users.LoginUser('donald','#duck99',ACreatedObject);
fUserObjectId:=ACreatedObject.ObjectID;
end
To Update the Installation with the User Object iD
Assuming you have a column 'User' in your Installation table on Parse as a pointer to _User class.
Within the PushEventsDeviceRegistered Event:
var
JO,JOP:TJSonObject; // System.JSON
O:TBackendEntityValue; // REST.Backend.MetaTypes
begin
if PushEvents.InstallationValue.TryGetObjectID(fInstallationObjectId) then
begin
try
JO:=TJSONObject.Create;
JOP:=TJSONObject.Create;
JOP.AddPair('__type','Pointer');
JOP.AddPair('className','_User');
JOP.AddPair('objectId',fUserObjectId);
JO.AddPair('User',JOP);
BackendStorage.Storage.UpdateObject('_Installation',
fInstallationObjectId,JO,O);
finally
JO.Free;
end;
end
end;
To Target the Push Message Based on User Name
Note, you could create the target via JSON objects,but I've used a string with formatting here.
const
Target = '{"where":{"User":{"$select":{"query":'+
'{"__type":"Pointer","className":"_User","where":'+
'{"username":"%s"}},"key":"objectId"}}}}';
begin
BackendPush.Target.Text:=Format(Target,['donald']);
BackendPush.Message:='Gratz on the Election Result';
BackendPush.Push;
end
Non Local Variables/Declarations
The following Delphi BaaS components were created at Design time.
ParseProvider: TParseProvider;
PushEvents: TPushEvents;
BackendUsers: TBackendUsers;
BackendStorage: TBackendStorage;
BackendPush: TBackendPush;
The following class (or global) variables are referred to:
fUserObjectId:string; // Must be set before push registration is activated.
fInstallationObjectId:string;
NOTE: The original code is fully tested, however I've cut/paste (and edited to remove non-relevant stuff) so forgive me if there are any cut/paste errors.

Related

Windev Quickbooks SDK OpenConnection2

I've been trying to find a way to connect my Windev application using the Quickbooks SDK.
I wish to connect to my local QB instance using the qbXML API.
I've been able to get a reference to the library using :
myconnection = new object Automation "QBXMLRP2.RequestProcessor"
However, when it comes to the OpenConnection2 method, I only get errors. Either "missing parameter" or "invalid parameter". I am aware that I should pass a "localQBD" type to the function, but I have not found out how to reference it. The following represents my invalid script.
myconnection>>OpenConnection2("","My Test App", localQBD)
How can I achieve a connection to QB through Windev?
After much searching, I have found that I was on the right path using the automation variable type.
However, I have yet to find how to reference the constants provided by the library. Instead, I declare them beforehand like so
CONSTANT
omSingleUser = 0
omMultiUser = 1
omDontCare = 2
qbStopOnError = 0
qbContinueOnError = 1
ctLocalQBD = 1
ctLocalQBDLaunchUI = 3
FIN
Which gives us this working example
myconnection = new object Automation "QBXMLRP2.RequestProcessor"
ticket = myconnection>>BeginSession("",::omDontCare)
XMLresponse = myconnection>>ProcessRequest(ticket,XMLrequest)
myconnection>>EndSession(ticket)
myconnection>>CloseConnection()
delete myconnection
A huge thanks goes to Frank Cazabon for showing me the proper constant values.
I have a complete external WinDev component that accesses QB and a helper program that can generate the WinDev calls in the correct order with the correct spelling and provides an OSR for all the QuickBooks fields and modules.
I have a similar product for the Clarion language and am in the final stages of the WinDev version. Contact me if you are interested. qbsnap at wybatap.com

Oracle Sql Developer 3.1 Unable to see Stored Procedure

Hi I am using Oracle SQL Developer 3.1.06 and connected to 11g EE. Whenever I will click edit in any procedure in the left pane, showing "create or replace" in the right side window.. I am not able to see any procedure code. I am able to see the procedure in same login in toad.
Are you sure the user you are logging in with is the owner of the objects?
You can check the owner by looking into the ALL_OBJECTS table:
SELECT * FROM ALL_OBJECTS WHERE OBJECT_NAME LIKE '%MYOBJECT%'
The user you are logging into could perhaps only have limited view rights preventing you from accessing the code. If you found the owner, you could browse in the connection window to other users and select the procedure from the relevant user. You should then be able to see everything.
I have a user called LOW_PRIVS.
They only have RESOURCE and CONNECT.
I create a procedure.
I open procedure.
Here is what we run to get the source code on a local procedure:
WITH src AS (
SELECT ROWNUM,
line,
text,
origin_con_id
FROM sys.all_source
WHERE type = :type
AND owner = :owner
AND name = :name
)
SELECT text
FROM src,
(
SELECT MAX(origin_con_id) max_orig
FROM src
)
WHERE origin_con_id = max_orig
ORDER BY line
We're hitting the ALL_SOURCE view that belongs to SYS. That should work for anyone.
But test and verify.
Note: I am on version 18.2 - that is many years newer than version 3.1. For best support, upgrade.

Why is COMMON_APPDATA returned as a null string on Windows XP

One of my users at a large university (with, I imagine, the aggressive security settings that university IT departments general have on their computers) is getting an empty string returned by Windows XP for CSIDL_COMMON_APPDATA or CSIDL_PERSONAL. (I'm not sure which of these is returning the empty string, because I haven't yet examined his computer to see how he's installed the software, but I'm pretty sure it's the COMMON_APPDATA...)
Has anyone encountered this or have suggestions on how to deal with this?
Here's the Delphi code I'm using to retrieve the value:
Function GetSpecialFolder( FolderID: Integer):String;
var
PIDL: PItemIDList;
Path: array[0..MAX_PATH] of Char;
begin
SHGetSpecialFolderLocation(Application.Handle, FolderID, PIDL);
SHGetPathFromIDList(PIDL, Path);
Result := Path;
end; { GetSpecialFolder }
ShowMessage(GetSpecialFolder(CSIDL_COMMON_APPDATA)); <--- This is an empty string
Edit:
Figuring out this API made me feel like I was chasing my tail - I went in circles trying to find the right call. This method and others similar to it are said to be deprecated by Microsoft (as well as by a earlier poster to this question (#TLama?) who subsequently deleted the post.) But, it seems like most of us, including me, regularly and safely ignore that status.
In my searches, I found a good answer here on SO from some time ago, including sample code for the non-deprecated way of doing this: what causes this error 'Unable to write to application file.ini'.
If you want to find out why an API call is failing you need to check the return values. That's what is missing in this code.
You need to treat each function on its own merits. Read the documentation on MSDN. In the case of SHGetSpecialFolderLocation, the return value is an HRESULT. For SHGetPathFromIDList you get back a BOOL. If that is FALSE then the call failed.
The likely culprit here is SHGetSpecialFolderLocation, the code that receives the CSIDL, but you must check for errors whenever you call Windows API functions.
Taking a look at the documentation for CSIDL we see this:
CSIDL_COMMON_APPDATA
Version 5.0. The file system directory that contains application data for all users. A typical path is C:\Documents and Settings\All
Users\Application Data. This folder is used for application data that
is not user specific. For example, an application can store a
spell-check dictionary, a database of clip art, or a log file in the
CSIDL_COMMON_APPDATA folder. This information will not roam and is
available to anyone using the computer.
If the machine has a shell version lower than 5.0, then this CSIDL value is not supported. That's the only documented failure mode for this CSIDL value. I don't think that applies to your situation, so you'll just have to see what the HRESULT status code has to say.

JEDI JVCL TJvProgramVersionCheck How to use HTTP

I'm wondering if someone has an example on how can be used the TJvProgramVersionCheck component performing the check via HTTP.
The example in the JVCL examples dir doesn't show how to use HTTP
thank you
The demo included in your $(JVCL)\Examples\JvProgramVersionCheck folder seems to be able to do so. Edit the properties of the JVProgramVersionHTTPLocation, and add the URL to it's VersionInfoLocation list (a TStrings). You can also set up any username, password, proxy, and port settings if needed.
You also need to add an OnLoadFileFromRemote event handler. I don't see anything in the demo that addresses that requirement, but the source code says:
{ Simple HTTP location class with no http logic.
The logic must be implemented manually in the OnLoadFileFromRemote event }
It appears from the parameters that event receives that you do your checking there:
function TJvProgramVersionFTPLocation.LoadFileFromRemoteInt(
const ARemotePath, ARemoteFileName, ALocalPath, ALocalFileName: string;
ABaseThread: TJvBaseThread): string;
So you'll need to add an event handler for this event, and then change the TJVProgramVersionCheck.LocationType property to pvltHTTP and run the demo. After testing, it seems you're provided the server and filename for the remote version, and a local path and temp filename for the file you download. The event handler's Result should be the full path and filename of the newly downloaded file. Your event handler should take care of the actual retrieval of the file.
There are a couple of additional types defined in JvProgramVersionCheck.pas, (TJvProgramVersionHTTPLocationICS and TJvProgramVersionHTTPLocationIndy, both protected by compiler defines so they don't exist in the default compilation. However, setting the ICS related define resulted in lots of compilation errors (it apparently was written against an old version of ICS), and setting the Indy define (and then setting it again to use Indy10 instead) allowed it to compile but didn't change any of the behavior. I'm going to look more into this later today.
Also, make sure that the VersionInfoLocation entry is only the URL (without the filename); the filename itself goes in the VersionInfoFileName property. If you put it in the URL, it gets repeated (as in http://localhost/Remote/ProjectVersions_http.iniProjectVersions_http.ini, and will fail anyway. (I found this while tracing through the debugger trying to solve the issue.)
Finally...
The solution is slightly (but not drastically) complicated. Here's what I did:
Copy JvProgramVersionCheck.pas to the demo folder. (It needs to be recompiled because of the next step.)
Go to Project->Options->Directories and Conditionals, and add the following line to the DEFINES entry:
USE_3RDPARTY_INDY10;USE_THIRDPARTY_INDY;
Delete the JvProgramVersionHTTPLocation component from the demo form.
Add a new private section to the form declaration:
private
HTTPLocation: TJvProgramVersionHTTPLocationIndy;
In the FormCreate event, add the following code:
procedure TForm1.FormCreate(Sender: TObject);
const
RemoteFileURL = 'http://localhost/';
RemoteFileName = 'ProjectVersions_http.ini';
begin
HTTPLocation := TJvProgramVersionHTTPLocationIndy.Create(Self); // Self means we don't free
HTTPLocation.VersionInfoLocationPathList.Add(RemoteFileURL);
HTTPLocation.VersionInfoFileName := RemoteFileName;
ProgramVersionCheck.LocationHTTP := HTTPLocation;
ProgramVersionCheck.LocationType := pvltHTTP;
VersionCheck; // This line is already there
end;
In the ProgramVersionCheck component properties, expand the VersionInfoFileOptions property, and change the FileFormat from hffXML to hffIni.
Delete or rename the versioninfolocal.ini from the demo's folder. (If you've run the app once, it stores the http location info, and the changes above are overwritten. This took a while to track down.)
Make sure your local http server is running, and the ProjectVersions_http.ini file is in the web root folder. You should then be able to run the demo. Once the form appears, click on the Edit History button to see the information retrieved from the remote version info file. You'll also have a new copy of the versioninfolocal.ini that has the saved configuration info you entered above.

TWordApplication and Word collision

I am using TWordApplication in Delphi. My app opens new instance of word and make something on its document. Problem is when i first run my app and next open real word exe. Word exe didnt open new word instance but it link to my app instance. So when my app write to its document all text appears on exe word visible to user.
WordApp := TWordApplication.Create(nil);
WordApp.ConnectKind := ckNewInstance;
(WordApp.Documents.Add(EmptyParam,EmptyParam,EmptyParam, varFalse ));
Then the user opens Word manually.
WordApp.Selection.Text := 'test test test';
And user see 'test test test' in manually opened Word.
If i first opens Word manually and starts my app all is ok.
This is default behaviour of Word, it uses a running instance. What you have to do is store a reference to the document you want to modify. So don't use ActiveDocument, but use the Document you stored. Because there is no guarantee that ActiveDocument is the document you think it is.
//starting Word
var
App: TWordApplication;
Doc: WordDocument;
begin
App := TWordApplication.Create(nil);
Doc := App.Documents.AddOld(EmptyVar, EmptyVar); //open new document
<..somewhere else..>
//modifying Word
Doc.DoWhateverIWant; // <--see? no ActiveDocument, so you are not
// modifying the users doc
Make sure you use
WordApp.ConnectKind := ckNewInstance;
to open your word application. Either do it in code (as above) or set the property at design time. This ensures that you are always running a new instance of Word and that it remains hidden unless you explicitely make it visible. Any user opening Word will then always get a different instance of Word and will not see what you have put on the document (unless you have saved it and they open the saved document).
From the doc:
Set ConnectKind to indicate how the
ConnectKind component establishes a
connection. ConnectKind establishes
the connection when the application is
run (if AutoConnect is True true) or
when the application calls the Connect
(or ConnectTo) method.
The following table lists the possible values:
//Value Meaning
//ckRunningOrNew Attach to a running server or create a new instance of the server.
//ckNewInstance Always create a new instance of the server.
//ckRunningInstance Only attach to a running instance of the server.
//ckRemote Bind to a remote instance of the server. When using this option,
// you must supply a value for RemoteMachineName.
//ckAttachToInterface Don't bind to the server. Instead, the application supplies an
// interface using the ConnectTo method, which is introduced in
// descendant classes. This option can't be used with the AutoConnect
// property.
Update
Actually, opening Word may have opened a different instance (that's how I remember it for D5/Word97), but at the moment Word does indeed re-use the instance opened by the application. So to avoid "scratching all over a word document manually opened by a user" you really do need to avoid using ActiveDocument as per The_Fox's answer.
According to http://support.microsoft.com/kb/210565 there are several command line switches that will cause Word to start a new instance. The one I have used with Word2003 is /x

Resources