You are not logged in.
I'm having a problem with invalid timestamps when making two requests in quick succession after logging in. The first request succeeds but the second one fails.
In the logs I've got: Invalid TimeStamp: expected >=-8, got 142
The problem seems to be in line 51786 of mormot.pas when result.fLastTimeStamp is less than fTimeStampCoherencyTicks, I assume causing an overflow:
if HexDisplayToCardinal(PTimeStamp,aTimeStamp) and
(fNoTimeStampCoherencyCheck or (result.fLastTimeStamp=0) or
(aTimeStamp>=result.fLastTimeStamp-fTimeStampCoherencyTicks)) then begincould using abs() could be a solution?:
(aTimeStamp>=abs(result.fLastTimeStamp-fTimeStampCoherencyTicks))) then beginAlso in line 51803 it's failing to log the timestamp value and looks like it should be:
Ctxt.Log.Log(sllUserAuth,'Invalid TimeStamp: expected >=%, got %',
[result.fLastTimeStamp-fTimeStampCoherencyTicks,Int64(aTimeStamp)],self); //<<< added Int64(aTimeStamp)I think there was a bug in the original code. in the crc32 function try changing this line:
crc = crc ^ (-1);to this:
crc = crc^0xFFFFFFFF; I just use HttpGet()
The photo looks like a Giacometti view of our mORMot!
I've found that synapse works well:
http://synapse.ararat.cz/doku.php/
It supports attachments and SSL connections
I've just seen this post on the embarcadero web site: https://www.embarcadero.com/br/products … tarter-faq
Can this free edition be used to compile SQLite?
I've noticed that c.bat in the sqlite folder has been edited and seems to point to a different compiler. Does it not use the free borland C++ builder 5.5 anymore?
The dates for the sample data in the MVC example seem to be awry (using delphi 2007 on windows 7). The version of ComputeMinimalData below should be better.
procedure TBlogApplication.ComputeMinimalData;
var info: TSQLBlogInfo;
article: TSQLArticle;
comment: TSQLComment;
tag: TSQLTag;
batch: TSQLRestBatch;
n,t: integer;
articles,tags,comments: TIDDynArray;
tmp: RawUTF8;
auto: IAutoFree; // mandatory only for FPC
tmpTime: TDateTime;
begin
auto := TSQLRecord.AutoFree([ // avoid several try..finally
@info,TSQLBlogInfo, @article,TSQLArticle, @comment,TSQLComment, @tag,TSQLTag]);
if not RestModel.Retrieve('',info) then begin // retrieve first item
info.Title := 'mORMot BLOG';
info.Language := 'en';
info.Description := 'Sample Blog Web Application using Synopse mORMot MVC';
info.Copyright := '©2016 <a href=http://synopse.info>Synopse Informatique</a>';
info.About := TSynTestCase.RandomTextParagraph(30,'!');
RestModel.Add(info,true);
end;
if RestModel.TableHasRows(TSQLArticle) then
exit;
tmp := StringFromFile('d:\download\2014-12-27-a8003957c2ae6bde5be6ea279c9c9ce4-backup.txt');
if tmp<>'' then begin
DotClearFlatImport(RestModel,tmp,fTagsLookup,'http://blog.synopse.info',
(TMVCRunOnRestServer(fMainRunner).Views as TMVCViewsMustache).ViewStaticFolder);
exit;
end;
SetLength(tags,32);
for n := 1 to length(tags) do begin
tag.Ident := 'Tag'+UInt32ToUtf8(n);
tag.IDValue := n*2; // force test TSQLTags layout
tags[n-1] := RestModel.Add(tag,true,true);
end;
fTagsLookup.Init(RestModel); // reload after initial fill
tmpTime := now - FAKEDATA_ARTICLESCOUNT;
batch := TSQLRestBatch.Create(RestModel,TSQLArticle,20000);
try
article.Author := TSQLAuthor(1);
article.AuthorName := 'synopse';
for n := 1 to FAKEDATA_ARTICLESCOUNT do begin
article.CreatedAt := TimeLogFromDateTime(tmpTime);
article.ModifiedAt := article.CreatedAt;
tmpTime := tmpTime +1;
article.SetPublishedMonth(article.CreatedAt);
//article.PublishedMonth := 2014*12+(n div 10);
article.Title := TSynTestCase.RandomTextParagraph(5,' ');
article.Abstract := TSynTestCase.RandomTextParagraph(30,'!');
article.Content := TSynTestCase.RandomTextParagraph(200,'.','http://megascroll.net');
article.Tags := nil;
for t := 1 to Random(6) do
article.TagsAddOrdered(tags[random(length(tags))],fTagsLookup);
batch.Add(article,true,false,[],true);
end;
if RestModel.BatchSend(batch,articles)=HTTP_SUCCESS then begin
fTagsLookup.SaveOccurence(RestModel);
comment.Author := article.Author;
comment.AuthorName := article.AuthorName;
batch.Reset(TSQLComment,20000);
for n := 1 to FAKEDATA_ARTICLESCOUNT*2 do begin
comment.Article := Pointer(articles[random(length(articles))]);
comment.Title := TSynTestCase.RandomTextParagraph(5,' ');
comment.Content := TSynTestCase.RandomTextParagraph(30,'.','http://megascroll.net');
batch.Add(Comment,true);
end;
RestModel.BatchSend(batch,comments)
end;
finally
batch.Free;
end;
end;Another very small thing - The base timestamped record doesn't need to be declared. It could use TSQLRecordTimed in mormot.pas instead of TSQLRecordTimeStamped
Thanks,
Just realised that I need to add the jwoAsJsonNotAsString option to get ID instead of rowID.
I'm also puzzled by the difference between 'ID' and 'RowID'.
If I use TSQLTableDB.getJSONValues(true) it returns ID
but with TSQLRecord.getJSONValues(true,true,soSelect) it returns RowID for the record number.
Can anyone explain the difference between ID and RowID?
Thanks,
Esmond
I've been playing with sample 30 (MVC Server) and noticed it's lacking much of a UI for editing blogs. www.salesforce.com have released some open source projects which look very professional and could help provide a javascript/html/bootstrap interface:
http://getfuelux.com/ has a pillbox component which could provide editing for tags. It also has a good looking datepicker.
http://beta.quilljs.com/ is a javascript editor which could provide an HTML editing mechanism - I'm sure someone will ask for this.
I guess the difficulty with quill and allowing HTML posts is malicious javascript injection etc. - especially if unknown users make comments.
Would these feature requests for the mustache unit make sense?:
1/ as well as escaped and non-escaped HTML variables could there be a third class of variable which is HTML white-listed-escaped? i.e. allow a few html tags to get through with limited attributes, a bit like quill. Something similar in javascript is http://htmlpurifier.org/. This seems better than BBcode as long as the white list is documented.
2/ hive off the section of code which escapes html in mustache.pas so that SOA functions could do this on-write rather than on-read (or is this premature optimization?).
+1 for method based services
Probably the 'static content compression' feature needs to be turned on in IIS.
Thanks ![]()
I can't get RecordLoadJSON to work with records containing TTimeLog.
But it seems to work if TTimeLog is defined as int64 (using delphi 2007).
I've put an example program below.
program test;
{$APPTYPE CONSOLE}
uses
SysUtils, SynCommons;
type
myJSON = packed record
myDate: TTimeLog;
s: string; //added to create some TypeInfo
end;
const
__myJSON = 'myDate:TTimeLog; s:string';
testString = '{"myDate":135305815903}';
var
myRecord: myJSON;
begin
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(myJSON),__myJSON);
RecordLoadJSON(myRecord,testString,TypeInfo(myJSON));
writeln(DateToStr(TimeLogToDateTime(myRecord.myDate))); //outputs 12/30/1899
//if myDate is defined as an Int64 then output is correct - 4/14/2016
writeln(DateToStr(TimeLogToDateTime(135305815903))); //outputs 4/14/2016
readln;
end.Is this a bug?
Thanks, I need to study the source code more.
Sorry, my question wasn't very clear. I've got a server which is basically defined like this:
type
TMyServer = class(TSQLRestServerDB)
published
procedure service_1(cTxt: TSQLRestServerURIContext);
procedure service_2(cTxt: TSQLRestServerURIContext);
...
end;This is implemented with method-based services. Is there a way to use mORMotMVC.pas without rewriting the services to use interfaces?
Is it possible to use TMVCApplication with method based services instead of interface based services?
Thanks for adding this option.
I slightly dread trying to handle 64bit IDs in javascript. My plan at the moment is to ignore IDs bigger than javascript's 53-bit limit for javascript clients - it's unlikely I'll need anything larger than 32bit.
Normally about 2000 chars in a URL is fine. Not sure why you have the 260 char limit.
Only solution I can think of is to find a way to shorten the URL
I've put an improved version of my typescript client on GitHub:
https://github.com/esmondb/mORMot-Typescript-client
No guarantees for 'fitness for purpose' but any feedback welcome!
I'm not completely sold on twitter's bootstrap. OpenUI5 and vcljs look really interesting. I tried bootstrap version 2, but needed to make quite a few tweaks for my use case. Then version 3 broke my tweaks and changed default css box-sizing causing more problems. Version 4 seems delayed.
It doesn't seem that active looking at the timeline:
http://sqlite.org/src4/timeline
But the Decimal Math feature looks interesting
Great
Thanks, it's all working now.
Many thanks
. It's working fine now.
This probably isn't related but I can't get the main sample 30 (MVC Blog) to run when compiled on Delphi 2007 and win7 64bit. It's giving an AV in the ComputeMinimalData procedure in MVCViewModel.pas. Line 207:
if RestModel.BatchSend(batch,articles)=HTML_SUCCESS then begincalls TSQLRestServerDB.MainEngineAdd in mORMotSQLite3.pas which causes an access violation at line 828:
AddInt64(TInt64DynArray(fBatchID),fBatchIDCount,result); Having trouble finding the solution
. Any help welcome!
Thanks but sorry I made a mistake in TSQLRecord.GetSQLCreate. Could the new fix below be applied.
This will probably break the search feature in sample 30 - MVC Server, for non-sqlite dbs. I guess this would need contentless FTS tables as before but with only an insert trigger and some sort of utility function to periodically update the FTS index by rebuilding it.
I wasn't quite sure why the fields in the main record were being concatenated into a single field in the fts record so I made a small change to allow multiple fts fields. If there is only one field in the FTS record it behaves as before and concatenates the main record fields, otherwise the fields in the FTS record definition must be the same or a subset of the main record's fields and they will be mapped across.
28695,28696c28695
< aModel.Tables[Props.fFTSWithoutContentTableIndex].SQLTableName+'",'+
< Props.fFTSWithoutContentExpression+',';
---
> aModel.Tables[Props.fFTSWithoutContentTableIndex].SQLTableName+'",';
28705,28706c28704
< if Props.fFTSWithoutContentExpression='' then
< result := result+Name+',';
---
> result := result+Name+',';
30083c30081,30083
< exp := exp+'||'' ''||new.'+ContentTableFieldNames[i];
---
> if high(ContentTableFieldNames) > 0 then
> exp := exp+',new.'+ ContentTableFieldNames[i] else
> exp := exp+'||'' ''||new.'+ContentTableFieldNames[i];
44200c44200
< fts,main,ftsmainfield: RawUTF8;
---
> fts,main,ftsfields: RawUTF8;
44211c44211
< ftsmainfield := Props.Props.MainFieldName(true);
---
> ftsfields := Props.Props.SQLTableSimpleFieldsNoRowID;
44221c44221
< [main,main,fts,ftsmainfield,Props.fFTSWithoutContentExpression]);
---
> [main,main,fts,ftsfields,Props.fFTSWithoutContentExpression]);
44224c44224
< [main,main,fts,ftsmainfield,Props.fFTSWithoutContentExpression]);
---
> [main,main,fts,ftsfields,Props.fFTSWithoutContentExpression]);Changing the following two lines in TSQLRecord.GetSQLCreate seems to fix the problem
28690 result := result+'content="'+aModel.Tables[Props.fFTSWithoutContentTableIndex].SQLTableName+'",'+Props.fFTSWithoutContentExpression+',';
28698 else if Props.fFTSWithoutContentExpression='' thenCould this patch be applied to mormot.pas?
28690c28690
< result := result+'content="",';
---
> result := result+'content="'+aModel.Tables[Props.fFTSWithoutContentTableIndex].SQLTableName+'",'+Props.fFTSWithoutContentExpression+',';
28698c28698
< [self,Name]) else
---
> [self,Name]) else if Props.fFTSWithoutContentExpression='' thenLooking at the sqlite docs http://www.sqlite.org/fts3.html#*fts4content I noticed
It is not possible to UPDATE or DELETE a row stored in a contentless FTS4 table. Attempting to do so is an error.
However, TSQLRecordFTS4.InitializeTable seems to set up DELETE and INSERT triggers on contentless FTS4 tables.
Should the table be created as an External Content FTS4 Table instead of contentless? (see https://www.sqlite.org/fts3.html#section_6_2_2)
I'm having a problem getting FTS4WithoutContent to work when updating records. It's giving this error: 'SQL logic error or missing database'.
I've put a test program below. Is the error from mormot or have I done something wrong?
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, mORMot, SynCommons, mORMotSQLite3, SynSQLite3Static;
type
TSQLMy_Record = class(TSQLRecord)
private
fName: RawUTF8;
published
property Name: RawUTF8 read fName write fName;
end;
TSQLMy_FTSRecord = class(TSQLRecordFTS4)
private
fName: RawUTF8;
published
property Name: RawUTF8 read fName write fName;
end;
function CreateModel: TSQLModel;
begin
result := TSQLModel.Create([TSQLMy_Record, TSQLMy_FTSRecord]);
result.Props[TSQLMy_FTSRecord].FTS4WithoutContent(TSQLMy_Record, [
'Name']);
end;
var
Model: TSQLModel;
Rest: TSQLRestServerDB;
rec: TSQLMy_Record;
begin
Model := CreateModel;
Rest := TSQLRestServerDB.Create(Model,'test.db3');
Rest.CreateMissingTables();
rec := TSQLMy_Record.Create;
rec.Name := 'Barack Obama';
Rest.Add(rec,True);
rec.Name := 'President Barack Obama';
Rest.Update(rec);
rec.Free;
Rest.Free;
Model.Free;
readln;
end.Hi AB,
Could I make a request for a blog post?
I've noticed your post in this forum: http://delphicodemonkey.blogspot.co.uk/ … -deux.html
What I would like is a KISS example of how to build delphi projects with a ms batch file. I've looked at MSBuild and got confused.
Thanks for the extra insight! I haven't had time to test any other units.
I don't normally use IDE plug-ins but has anyone found FixInsight useful?
Trying it out on mormot.pas doesn't seem to bring up any serious issues.
There are a few empty else blocks and a couple of missing 'inherited;' statements in overriden constructors which I assume are harmless.
And these warnings which I also assume are harmless:
[FixInsight Warning] mORMot.pas(34128): W509 Unreachable code
[FixInsight Warning] mORMot.pas(48157): W509 Unreachable code
[FixInsight Warning] mORMot.pas(49273): W515 Suspect FREE call
I had a similar problem with a service and chose 409 as the http error code. I'm a bit confused with how to handle mORMot errors with ajax. Are errors within mORMot only returned with an ok 200 response with the error encoded as JSON within the response or does it use http error codes?
Thanks, yes it does work. Doing wildcard style searches isn't easy but I've found this works -
SELECT term FROM ft_terms WHERE term BETWEEN 'appl' AND 'appl' ||
CAST(x'FF' AS CHAR)
Does mORMot have any features to make use of fts4aux: https://www.sqlite.org/fts3.html#fts4aux ?
I've noticed it metioned in the update below but can't see how to use it with mORMot.
http://synopse.info/forum/viewtopic.php?id=299
Thanks
I'm trying to update a TintegerArray field with TSQLRest.UpdateField but get this error: 'ESynException with message "TJSONSerializer.AddVariant(VType=8195)".'
TSQLRest.Update with the whole record works fine. (using SQLite)
What's wrong?
Could IntegerDynArrayToCSV change it's behaviour so that the Prefix and Suffix are returned with an empty array?
It would need the following changes at line 22603 of SynCommons.pas:
function IntegerDynArrayToCSV(const Values: array of integer; ValuesCount: integer;
const Prefix: RawUTF8=''; const Suffix: RawUTF8=''): RawUTF8;
type
TInts16 = packed array[word] of string[15]; // shortstring are faster (no heap allocation)
var i, L, Len: PtrInt;
tmp: array[0..15] of AnsiChar;
ints: ^TInts16;
P: PAnsiChar;
begin
result := '';
if ValuesCount=0 then
exit;
...to
function IntegerDynArrayToCSV(const Values: array of integer; ValuesCount: integer;
const Prefix: RawUTF8=''; const Suffix: RawUTF8=''): RawUTF8;
type
TInts16 = packed array[word] of string[15]; // shortstring are faster (no heap allocation)
var i, L, Len: PtrInt;
tmp: array[0..15] of AnsiChar;
ints: ^TInts16;
P: PAnsiChar;
begin
result := '';
if ValuesCount=0 then begin
result := Prefix + Suffix;
exit;
end;
...The following Int64DynArrayToCSV function would need the same change for consistency.
Maybe there is something wrong with TSQLAuthGroup.SQLAccessRights. Perhaps try setting it to:
const
SERVICE_ACCESS_RIGHTS: TSQLAccessRights =
(AllowRemoteExecute: [reService];
GET: []; POST: [];
PUT: []; DELETE: []);I got the 403 error in a similar situation the other day. I had forgotten to set TSQLAuthGroup.SessionTimeout which reverted to 0.
Thanks, understand it better now and all works. I was doing validation server side as I was using ajax and checking for a unique field.
thought of using StringToUTF8() but was thinking it would be more efficient to do the function on the client with UTF8ToString() instead of the server.
I'll have a look at LoadResStringTranslate().
Thanks
I'm using TSQLRecord.Validate in a service. Would it be possible to change it to return rawUTF8 instead of string?
Also what's the best way to override the resourcestrings in SynCommons.pas?
Many thanks
Many thanks. I think a need to create a service.
This probably doesn't matter but firebug gives a silent parsing error with TSQLRestServerURIContext.Success(). Should the JSON content-type header be omitted with Success() as an empty string isn't valid JSON?
I'm using mORMot with sqlite and the default authentication using TSQLAuthUser.
I've created a parallel table to store extended user details like contact details etc. What's the best way to protect this table so that a user can only view and update their own record? Or would it be easier to extend TSQLAuthUser and use a service to access this user record?
Many thanks
Could SessionCreate in mORMot.pas be changed to return also the user's group id? I'm using an ajax client and want to adjust the UI depending on group.
Changing line 43821 seems the simplest way:
procedure TSQLRestServerAuthentication.SessionCreate(Ctxt: TSQLRestServerURIContext;
var User: TSQLAuthUser);
var Session: TAuthSession;
begin
if User<>nil then
try // now client is authenticated -> create a session
fServer.SessionCreate(User,Ctxt,Session); // call Ctxt.AuthenticationFailed on error
if Session<>nil then
// CHANGED LINE 43821:
Ctxt.Returns(['result',Session.fPrivateSalt,'logonname',Session.User.LogonName,'groupid',Session.User.GroupRights.ID]);
finally
User.Free;
end;
end;I think they should give away the professional version of Delphi to students and hobbyists but on the understanding it's only used for non-commercial uses. I'm sure 99% of people would upgrade if they started making money from it. PKzip, for example, was shareware but was apparently profitable to it's company.
My first version of Delphi was version 3 which I got on the cover of a UK computer mag. I just paid £20 for the printed docs. Then bought Delphi 5 as a shrink wrapped box off eBay and upgraded it a couple of times. If I'd had to pay the full price I wouldn't have used it.