#151 Re: mORMot 1 » Dynamic named array as input » 2015-10-05 12:04:59

Thanks edwin.  I can do a wrapper function and then just use that when calling via ajax and use the real function for delphi clients.  However, I suspect this will add a lot of overhead and will need to be done throughout.

Any suggestions what would be the most efficient way of converting the json string to the array?

#152 Re: mORMot 1 » Dynamic named array as input » 2015-10-05 11:12:39

Unfortunately posting the values causes a 406 Not Acceptable error.

var dataString = {"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}]};
jQuery.ajax({
		type: "POST",
		dataType: "json",
		url: MAIN_URL + '/Staff/FilterStaff',
		data: dataString,
		timeout: 2000
	});

#153 mORMot 1 » Dynamic named array as input » 2015-10-05 10:49:14

squirrel
Replies: 11

What would be the correct format to send a named dynamic array to an interface function?

I declared the following as a test:

  TFilterType = record
    name: string;
    value: string;
    comparetype: string;
  end;
  TFilterList = array of TFilterType;

...

function TStaff.FilterStaff(const filters: TFilterList): TFilterList;
begin
  Log('Received filters: '+IntToStr(length(filters)) );

  setlength(result, 2);
  result[0].name := 'name1';
  result[0].value := 'value1';
  result[0].comparetype := '>';
  result[1].name := 'name2';
  result[1].value := 'value2';
  result[1].comparetype := '=';
end;

The function correctly returns

{"result":[[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype"
:"="}]]}

But when sending

var dataString = {"filters":[{"name":"name1","value":"value1","comparetype":">"},{"name":"name2","value":"value2","comparetype":"="}]};

...

http://localhost:8080/root/Staff/FilterStaff?filters%5B0%5D%5Bname%5D=name1&filters%5B0%5D%5Bvalue%5D=value1&filters%5B0%5D%5Bcomparetype%5D=%3E&filters%5B1%5D%5Bname%5D=name2&filters%5B1%5D%5Bvalue%5D=value2&filters%5B1%5D%5Bcomparetype%5D=%3D&session_signature=3eaeb14d00379c791c58bcc3

an empty array is received.

#155 Re: mORMot 1 » 500 Internal Server Error When using custom authentication » 2015-09-28 09:12:07

Thanks, what would be the correct way of setting the session timeout?
I am not using orm, just my own services, so will have to set it manually.

#156 Re: mORMot 1 » 500 Internal Server Error When using custom authentication » 2015-09-28 09:02:18

The 403 issue is confusing me.  Not sure where to place breakpoints anymore.  From somewhere, mormot gets an Admin user.  When using Admin as username with whatever I set the Result.PasswordPlain in GetUser, it works and allows my function calls.  Using any other username, such as that set in Result.LogonName in GetUser, it seems to authenticate ok, but then doesn't allow my function calls.  Are there any hardcoded usernames somewhere?

The access violation happens when setting SessionTimeout in the GetUser function.  It looks like Result.GroupRights is not accessible when trying to set the value.  Nothing really that I can debug at that stage.

function TMyAuthentication.GetUser(Ctxt: TSQLRestServerURIContext; const aUserName: RawUTF8): TSQLAuthUser;
begin
  Result := TSQLAuthUser.Create;
  Result.IDValue := 10;
  Result.LogonName := 'johnny';
  Result.DisplayName := Result.LogonName;
  Result.PasswordPlain := 'abc';
  Result.GroupRights := TSQLAuthGroup(2); // for 'Admin'
  Result.GroupRights.SessionTimeout := 1;
end;

#157 Re: mORMot 1 » 500 Internal Server Error When using custom authentication » 2015-09-25 12:15:57

Perfect, thanks.  I now no longer get the 500 error, but noticed something strange.  Given the example above, after logging in using any string as a password, the sesion authenticates and I get the message that I successfully logged in.  but using any functions returns 403 Forbidden.

However, using abc as a password, I still get the message that I successfully authenticated, but my functions are able to be called.  So it looks like, at some stage when checking if a function can be executed, my checkpassword function is ignored and a direct compare is done between the PasswordPlain value set and that sent to log in.  So does that mean that I need to also override another function to compute the hash, or should I expect the example above to work as-is?

Does the implimentation you provided above also mean that I can no longer set the session timeout value?  Trying to set Result.GroupRights.SessionTimeout results in an access violation.

#158 mORMot 1 » 500 Internal Server Error When using custom authentication » 2015-09-25 11:50:27

squirrel
Replies: 9

Hi AB

When using custom authentication, I get 500 Internal Server Error when the authentication succeeds, however when it fails, it works as expected.  It looks like it happens at SessionCreate and can be because of groups, but I'm not sure what I do wrong (just tested on latest nightly build):

  TMyAuthentication = class(TSQLRestServerAuthenticationDefault)
  private
    function CheckPassword(Ctxt: TSQLRestServerURIContext; User: TSQLAuthUser; const aClientNonce, aPassWord: RawUTF8): boolean; override;
    function GetUser(Ctxt: TSQLRestServerURIContext; const aUserName: RawUTF8): TSQLAuthUser; override;
  protected
  end;

  aRestServer := TSQLRestServerFullMemory.Create(aModel, false); // authentication=false
  aRestServer.AuthenticationRegister([TMyAuthentication]);

function TMyAuthentication.CheckPassword(
  Ctxt: TSQLRestServerURIContext; User: TSQLAuthUser; const aClientNonce,
  aPassWord: RawUTF8): boolean;
begin
  result := true; //aPassword = 'abc';
end;

function TMyAuthentication.GetUser(Ctxt: TSQLRestServerURIContext; const aUserName: RawUTF8): TSQLAuthUser;
begin
  Result := TSQLAuthUser.Create;
  Result.IDValue := 10;
  Result.LogonName := 'johnny';
  Result.DisplayName := Result.LogonName;
  Result.PasswordPlain := 'abc';
  Result.GroupRights := TSQLAuthGroup.Create;
  Result.GroupRights.SessionTimeout := 20;
  Result.GroupRights.AccessRights := 'Admin';
end;

Do you have anything to point me in the right direction?

#159 Re: mORMot 1 » Connection pools and thread safety » 2015-09-25 06:17:20

Thanks.  As per my test code, I already use TSQLRestServerFullMemory.  How does that bring the connection to the interfaces?  Is there a property that I need to access in the interface's functions?

I tried creating a class from which all my instances can inherit, but it doesn't look as if the connection is available when used in the TStaff class.  Would this be the correct way to access a specific created instance?  The Get call currently generates an access violation.

TMyInterface = class(TInterfacedObject)
private
public
  DBConnection: TSQLDBConnectionProperties;
end;

TStaff = class(TMyInterface, IStaff)
private
public
  function GetNickname(const aUserID: string):string;
  function WhoAmI: string;
end;

function TStaff.GetNickname(const aUserID: string): string;
var
  Res : ISQLDBRows;
begin
  Result := '';
  Res := DbConnection.Execute('select nickname from tblstaff where UserID=? ', [aUserID] );
  if Res.Step then
    Result := Res['nickname'];
end;
//This looks like it creates a copy of the interface and does not return the instance in the server,
//so setting properties here leave them nil in the server instance
if aRestServer.Services['Staff'].Get(obj) then
begin
  TMyInterface(obj).DBConnection := aConnection;
  showmessage(TStaff(obj).GetNickname('0')); //this works, but not when calling from ajax, since dbconnection then is nil
end;

//this does not bring the server instance back either, just give an AV
for I := 0 to aRestServer.Services.Count -1 do
  if aRestServer.Services.Index(I).Get(obj) then  //Access Violation here
    TMyInterface(obj).DBConnection := aConnection

//this works, but requires me to do for every service, no for loop
TMyInterface(aRestServer.Service<IStaff>).DBConnection := aConnection;

Now a more basic question remains: how to end a session from ajax?  I currently do the auth? call to authenticate, but what do I call to log out and ensure that a session can't be re-used? This always returns 400 Bad Request but does seem to kill the session (all calls after that returns 403 Forbidden):

http://localhost:8080/root/auth?session=184464650&UserName=admin&session_signature=0afeb50a0003f9f9d88a6677

#160 Re: mORMot 1 » Connection pools and thread safety » 2015-09-25 05:36:53

Is there a different way of passing the connection on to the TInterfacedObjects?

#161 Re: mORMot 1 » Connection pools and thread safety » 2015-09-23 09:30:20

Yes, squirrels and marmots often share food tongue

To pass on the connection, I followed something done by a user in one of the forum posts and created this little test:

  aConnection := TODBCConnectionProperties.Create('',ConnectionStr,'','');
  aRestServer := TSQLRestServerFullMemory.Create(aModel, false);
  aRestServer.AuthenticationRegister([TMyAuthentication]);
  aRestServer.ServiceDefine(TSales.Create(aConnection),[ISales]);
  aRestServer.ServiceDefine(TStaff,[IStaff], sicShared);

My auth for this test is also currently as simple as possible:

  TMyAuthentication= class(TSQLRestServerAuthenticationDefault)
  protected
    function CheckPassword(Ctxt: TSQLRestServerURIContext; User: TSQLAuthUser; const aClientNonce, aPassWord: RawUTF8): boolean; override;
  end;

  function TMyAuthentication.CheckPassword(Ctxt: TSQLRestServerURIContext; User: TSQLAuthUser; const aClientNonce, aPassWord: RawUTF8): boolean;
  begin
    result := aPassword = 'abc';
  end;

I then defined a WhoAmI function in Both TSales and TStaff.  When calling the Sales.WhoAmI function, it always returns 403 Forbidden, but Staff.WhoAmI always works as expected, depending on whether the authentication passed or failed. The WhoAmI function is also basic and doesn't perform any logic:

function TStaff.WhoAmI: string;
begin
  result := 'I am Somebody';
end;

Not sure if this is relevant, but I'm testing using Ajax, but will use the exact same function calls from a Delphi client.

Any advice would be super helpful.  I'm still finding my feet, but the more I see, the more I like it.

#162 mORMot 1 » Connection pools and thread safety » 2015-09-22 18:59:55

squirrel
Replies: 5

Hi

I've decided to not go the orm route so I can reuse some of our legacy queries.  For now, I decided to have a simple scenario where a function call will execute the TSQLDBStatement and return the results as json using FetchAllToJSON. 

How does the connection pools work then?  Do I need to create a new connection in every function, or should I declare the TSQLDBConnectionProperties.NewConnection globally so that NewConnection.NewStatement can be used in every function?  This does not sound thread safe, is there an alternative?

Given the complexities of the existing legacy code, I'll also have to do custom authentication, which will mean that the login query will run before a session is created and the normal queries after a session is created.  Will this affect the connection pool, or will this work the same as the normal queries?  The TSQLHttpServer is created in the Main thread.

Sorry if I don't express my questions well.  If anything is unclear I'll try to restate.

#163 Re: mORMot 1 » Mysql ODBC connection on 64bit Windows » 2015-08-14 10:18:49

1) For future readers:  It seems that the field that replaces ID is not allowed to be part of the TSQLRecord definition.  If it is, it correctly creates the table and then try to add it on again after creating the table.  After removing the TeamId field from the TSQLRecord class it works as expected.

2) Are there any options for statically linking the 64bit in the exe as well?  Do 64bit obj files need to be generated, or is this not possible / available?

#164 Re: mORMot 1 » Mysql ODBC connection on 64bit Windows » 2015-08-14 06:45:40

Thanks for the quick response.

1) This is a blank database.  If I don't call the Mapfield line, the table is successfully created.  I drop table manually after every test. 

2) Does that mean that I need to distribute an unreleased and unsupported version of SqlLite with all my applications and keep it up to date for something we don't use?  I am a bit confused about this.  I've searched my hard drive and don't have the 32bit version of SqlLite anywhere on it, yet the sample works.  But rebuilding the same code in 64bit gives the error.  Is the 64bit dll you distribute altered or different from the standard dll to make it a requirement?

3) I was able to resolve this, thanks

#165 mORMot 1 » Mysql ODBC connection on 64bit Windows » 2015-08-13 09:50:38

squirrel
Replies: 5

Good day

I am hoping to use the mORMot framework as a middle layer between our legacy databases and external applications (both Delphi and Web).  Could you please assist with the following questions?

1) Is it possible to use ORM and have an integer primary key that is called anything other than ID?  eg Change the primary key name to TeamID or CustomerID?  All tables already have autoincrementing integer primary keys. Edit: I assumed it would be by doing something like this:

aModel.Props[TSQLRecordTblTeams].ExternalDB.MapField('ID','TeamID');

but this results in the following error when calling CreateMissingTables:

Error SQLITE_ERROR (1) using 3.8.11.1 - ''TSQLRestStorageExternal.Create: TSQLRecordTblTeams: unable to create external missing field TblTeams.TeamID - SQL="ALTER TABLE TblTeams ADD TeamID bigint"'' extended_errcode=1

2) When building example 28 in 32 bit using a 32bit mysql dsn connection, the example works perfectly.  Building the same code in 64bit and using a 64bit dsn connection, I get the error:

No SQLite3 libray available: you shall either add SynSQLite3Static to your project uses clause or run sqlite3 := TSQLite3LibraryDynamic.Create(..).

  I do not intend using SqlLite at all, only Mysql and only in 64bit.  Is this possible?

3) When trying to use the full connection string instead of a dsn, the error

Data source name not found and no default driver specified (0) is returned.

  Is there anything specific that needs to be specified as part of the connection string?  Sample code from example 28 altered with mysql connection string:
 

aProps := TODBCConnectionProperties.Create('','DRIVER=MySQL ODBC 5.3 Unicode Driver;SERVER=localhost;DATABASE=testdb;USER=root;PASSWORD=testpasswd;Option=3;Port=3306','','');

Thanks for the excellent examples you distribute with the code.  If it wasn't for them using the framework wouldn't have been possible.

Board footer

Powered by FluxBB