diff --git a/README.md b/README.md index c37c08c6..bd6d2062 100644 --- a/README.md +++ b/README.md @@ -269,13 +269,13 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma - ✅ Improved! The unit tests fully test PostgreSQL, FirebirdSQL and SQLite while testing MVCActiveRecord framework. The other engines are tested using `activerecord_showcase` sample project. -- ✅ Improved! MVCActiveRecord doeas a better job to handle TDate/TTime/TDateTime types for SQLite (it is automatic because SQLite doesn't support date/time types). +- ✅ Improved! MVCActiveRecord does a better job to handle TDate/TTime/TDateTime types for SQLite (it is automatic because SQLite doesn't support date/time types). - ✅ Improved! PostgreSQL, FirebirdSQL, Interbase and SQLite now support tablename and fields with spaces. - ✅ Improved Nullable Types. Now it's possible to assign `nil` to a nullable type and to check its state using the new property `IsNull` which is the negation of the already available property `HasValue`. -- ✅ Improved! Now `TMVCStaticFileMiddleware` is able to manage high-level criteria to show/hide/mask specific files in the documetn web root. Check [Issue 548](https://github.com/danieleteti/delphimvcframework/issues/548) and the updated sample `samples\middleware_staticfiles\` for more info. +- ✅ Improved! Now `TMVCStaticFileMiddleware` is able to manage high-level criteria to show/hide/mask specific files in the document web root. Check [Issue 548](https://github.com/danieleteti/delphimvcframework/issues/548) and the updated sample `samples\middleware_staticfiles\` for more info. - ✅ Improved! In case of multiple MVCPath, Swagger consider only the first one (Thanks to V. Ferri and our sponsors) @@ -1415,6 +1415,11 @@ The current beta release is named 3.2.3-radium-beta. If you want to stay on the- ### What's New in 3.2.3-radium-beta - Fixed a rendering problem in swagger interface format in case of specific JSON structure +- Default error responses contains the official "reason string" associated to the HTTP status code (this can be a breaking change for some generic client which doesn't correctly interpret the http status code) +- Added static method `HTTP_STATUS.ReasonStringFor(HTTPStatusCode)` wich returns the standard `ReasonString` for a given HTTP status code. +- Improved handling of `TMVCErrorResponse` information +- mid-air-collision handling now uses SHA1 instead of MD5 +- Added `MVCFramework.Commons.MVC_HTTP_STATUS_CODES` const array containing all the HTTP status codes wich its `ReasonString` ## Trainings, consultancy or custom development service diff --git a/samples/activerecord_restful_crud/Entities.pas b/samples/activerecord_restful_crud/Entities.pas index 653e6d54..42e9e1a4 100644 --- a/samples/activerecord_restful_crud/Entities.pas +++ b/samples/activerecord_restful_crud/Entities.pas @@ -7,7 +7,10 @@ uses MVCFramework.ActiveRecord, MVCFramework.Nullables, System.Classes, - MVCFramework, System.Generics.Collections; + System.DateUtils, + MVCFramework, + MVCFramework.Utils, + System.Generics.Collections; type @@ -51,6 +54,8 @@ type public constructor Create; override; destructor Destroy; override; + function GetUniqueString: String; + procedure Assign(ActiveRecord: TMVCActiveRecord); override; property ID: Int64 read fID write SetID; [MVCNameAs('person_surname')] property LastName: string read fLastName write SetLastName; @@ -119,11 +124,28 @@ type implementation uses - System.DateUtils, System.SysUtils; { TPersona } +procedure TPerson.Assign(ActiveRecord: TMVCActiveRecord); +begin + if ActiveRecord is TPerson then + begin + var lPerson := TPerson(ActiveRecord); + Self.LastName := lPerson.LastName; + Self.FirstName := lPerson.FirstName; + Self.DOB := lPerson.DOB; + Self.IsMale := lPerson.IsMale; + Self.Note := lPerson.Note; + Self.Photo.Size := 0; + Self.Photo.CopyFrom(lPerson.Photo); + Self.Photo.Position := 0; + end + else + inherited; +end; + constructor TPerson.Create; begin inherited; @@ -141,6 +163,17 @@ begin Result := fFullName; end; +function TPerson.GetUniqueString: String; +begin + Result := + fID.ToString + '|' + + fFirstName + '|' + + fLastName + '|' + + DateToISODate(fDOB.ValueOrDefault) + '|' + + BoolToStr(fIsMale.ValueOrDefault, True) + '|' + + GetSHA1HashFromStream(fPhoto); +end; + procedure TPerson.OnAfterLoad; begin inherited; @@ -157,7 +190,6 @@ end; procedure TPerson.OnBeforeInsert; begin inherited; - // TMemoryStream(fPhoto).LoadFromFile('C:\DEV\dmvcframework\samples\_\customer_small.png'); end; procedure TPerson.OnBeforeInsertOrUpdate; diff --git a/samples/activerecord_restful_crud/activerecord_restful_crud.dpr b/samples/activerecord_restful_crud/activerecord_restful_crud.dpr index d3492b1c..33f6da6d 100644 --- a/samples/activerecord_restful_crud/activerecord_restful_crud.dpr +++ b/samples/activerecord_restful_crud/activerecord_restful_crud.dpr @@ -67,6 +67,7 @@ begin lServer.MaxConnections := 0; lServer.ListenQueue := 200; lServer.Active := True; + WriteLn('Running on port ', APort); Write('CTRL+C to Quit'); WaitForTerminationSignal; finally diff --git a/samples/activerecord_restful_crud/activerecord_restful_crud.dproj b/samples/activerecord_restful_crud/activerecord_restful_crud.dproj index e55877a0..aa8d9b92 100644 --- a/samples/activerecord_restful_crud/activerecord_restful_crud.dproj +++ b/samples/activerecord_restful_crud/activerecord_restful_crud.dproj @@ -7,7 +7,7 @@ 32897 Console None - 19.4 + 19.5 Win32 @@ -183,7 +183,7 @@ True False - + true @@ -199,12 +199,7 @@ true - - - activerecord_restful_crud.exe - true - - + 1 @@ -223,16 +218,6 @@ 64 - - - classes - 1 - - - classes - 1 - - res\xml @@ -556,7 +541,7 @@ 1 .dylib - + 1 .dylib @@ -590,7 +575,7 @@ 0 - + 0 @@ -611,13 +596,17 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -627,137 +616,27 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -767,7 +646,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -777,7 +656,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -787,7 +666,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -797,7 +676,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -807,191 +686,37 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1001,7 +726,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1011,7 +736,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1021,7 +746,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1031,7 +756,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1041,7 +766,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1051,7 +776,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1061,7 +786,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1083,8 +808,11 @@ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1 + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + - @@ -1095,7 +823,7 @@ 1 - + 1 @@ -1131,7 +859,7 @@ 1 - + 1 @@ -1188,6 +916,7 @@ + diff --git a/samples/articles_crud_server/articles_crud.dproj b/samples/articles_crud_server/articles_crud.dproj index 8d863706..9b745001 100644 --- a/samples/articles_crud_server/articles_crud.dproj +++ b/samples/articles_crud_server/articles_crud.dproj @@ -1,7 +1,7 @@  {41237016-48D9-45F1-8FFC-66D1B61A206B} - 19.4 + 19.5 VCL articles_crud.dpr True @@ -163,181 +163,36 @@ Embarcadero C++Builder Office XP Servers Package - - - - articles_crud.exe - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - - - - .\ - true - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 @@ -356,16 +211,6 @@ 64 - - - classes - 1 - - - classes - 1 - - res\xml @@ -408,7 +253,6 @@ 1 - library\lib\armeabi-v7a @@ -690,7 +534,7 @@ 1 .dylib - + 1 .dylib @@ -724,7 +568,7 @@ 0 - + 0 @@ -745,13 +589,17 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -761,181 +609,27 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -945,7 +639,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -955,7 +649,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -965,7 +659,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -975,7 +669,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -985,191 +679,37 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1179,7 +719,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1189,7 +729,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1199,7 +739,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1209,7 +749,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1219,7 +759,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1229,7 +769,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1239,7 +779,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1261,8 +801,11 @@ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1 + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + - @@ -1273,7 +816,7 @@ 1 - + 1 @@ -1309,7 +852,7 @@ 1 - + 1 @@ -1366,6 +909,7 @@ + diff --git a/samples/avoid_mid_air_collisions_sample/MainControllerU.pas b/samples/avoid_mid_air_collisions_sample/MainControllerU.pas index d2083c08..891f5fe3 100644 --- a/samples/avoid_mid_air_collisions_sample/MainControllerU.pas +++ b/samples/avoid_mid_air_collisions_sample/MainControllerU.pas @@ -3,35 +3,17 @@ unit MainControllerU; interface uses - MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons; + MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons, Entities; type - [MVCNameCase(ncCamelCase)] - TPerson = class - private - fName: String; - fSurname: String; - fID: Integer; - public - function GetHash: String; - class function GetNew(const id: Integer; const Name, Surname: String): TPerson; - property ID: Integer read fID write fID; - property Name: String read fName write fName; - property Surname: String read fSurname write fSurname; - end; - - [MVCPath('/api/people')] TMyController = class(TMVCController) - private - function GetPersonByID(const ID: Integer): TPerson; - procedure UpdatePersonByID(const ID: Integer; const Person: TPerson); public [MVCPath] [MVCHTTPMethod([httpGET])] - procedure Index; - public - // Sample CRUD Actions for a "person" entity + procedure GetPeople; + + [MVCPath('/($id)')] [MVCHTTPMethod([httpGET])] procedure Getperson(id: Integer); @@ -55,37 +37,19 @@ implementation uses System.SysUtils, MVCFramework.Logger, System.StrUtils, MVCFramework.Cache, - System.Rtti, MVCFramework.Rtti.Utils; + System.Rtti, MVCFramework.Rtti.Utils, MVCFramework.ActiveRecord; -procedure TMyController.Index; +procedure TMyController.GetPeople; begin - // use Context property to access to the HTTP request and response - Render('Hello DelphiMVCFramework World'); -end; - -function TMyController.GetPersonByID(const ID: Integer): TPerson; -var - lPerson: TPerson; -begin - lPerson := nil; - if not TMVCCacheSingleton.Instance.ExecOnItemWithWriteLock(id.ToString, - procedure(Value: TValue) - begin - lPerson := TRttiUtils.Clone(Value.AsObject) as TPerson; - end) then - begin - raise EMVCException.Create(HTTP_STATUS.NotFound, 'Person not found'); - end; - Result := lPerson; + Render(ObjectDict().Add('people', TMVCActiveRecord.All)); end; procedure TMyController.Getperson(id: Integer); var - lItem: TMVCCacheItem; lPerson: TPerson; begin - lPerson := GetPersonByID(id); - SetETag(lPerson.GetHash); + lPerson := TMVCActiveRecord.GetByPK(ID); + SetETag(lPerson.GetUniqueString); Render(lPerson, True); end; @@ -111,57 +75,43 @@ end; procedure TMyController.UpdatePerson(id: Integer; [MVCFromBody] const Person: TPerson); var - lItem: TMVCCacheItem; lPerson: TPerson; begin // retrieve data from storage - lPerson := GetPersonByID(id); + lPerson := TMVCActiveRecord.GetByPK(ID); + try + //check if the client modified the current version (a.k.a. mid-air collisions) + //raises an exception if client send a wrong If-Match header value + CheckIfMatch(lPerson.GetUniqueString); - //check if the client modified the current version (a.k.a. mid-air collisions) - //raises an exception if client send a wrong If-Match header value - CheckIfMatch(lPerson.GetHash); + //perform the actual update and save to the storage + lPerson.Assign(Person); + lPerson.Update(); - //perform the actual update and save to the storage - lPerson.Name := Person.Name; - lPerson.Surname := Person.Surname; - UpdatePersonByID(lPerson.ID, lPerson); + //set the new ETag value base on the data status + SetETag(lPerson.GetUniqueString); - //set the new ETag value base on the data status - SetETag(lPerson.GetHash); - - //reply with a 200 OK - Render(HTTP_STATUS.OK); + //reply with a 200 OK + Render(HTTP_STATUS.OK); + finally + lPerson.Free; + end; end; -procedure TMyController.UpdatePersonByID(const ID: Integer; - const Person: TPerson); -begin - TMVCCacheSingleton.Instance.SetValue(ID.ToString, Person); -end; procedure TMyController.DeletePerson(id: Integer); var lPerson: TPerson; begin - lPerson := GetPersonByID(ID); - CheckIfMatch(lPerson.GetHash); - TMVCCacheSingleton.Instance.RemoveItem(ID.ToString); - Render204NoContent(); -end; - -{ TPerson } - -function TPerson.GetHash: String; -begin - Result := Format('%d|%s|%s', [fID, fName, fSurname]); -end; - -class function TPerson.GetNew(const id: Integer; const Name, Surname: String): TPerson; -begin - Result := TPerson.Create; - Result.fID := id; - Result.fName := Name; - Result.fSurname := Surname; + lPerson := TMVCActiveRecord.GetByPK(ID); + try + CheckIfMatch(lPerson.GetUniqueString); + lPerson.Delete(); + Render204NoContent(); + except + lPerson.Free; + raise; + end; end; end. diff --git a/samples/avoid_mid_air_collisions_sample/WebModuleU.pas b/samples/avoid_mid_air_collisions_sample/WebModuleU.pas index fdb73ef0..c8db1d7b 100644 --- a/samples/avoid_mid_air_collisions_sample/WebModuleU.pas +++ b/samples/avoid_mid_air_collisions_sample/WebModuleU.pas @@ -81,17 +81,18 @@ begin // CORS middleware handles... well, CORS //FMVC.AddMiddleware(TMVCCORSMiddleware.Create); - + // Simplifies TMVCActiveRecord connection definition - //FMVC.AddMiddleware(TMVCActiveRecordMiddleware.Create('MyConnDef','FDConnectionDefs.ini')); - + FMVC.AddMiddleware(TMVCActiveRecordMiddleware.Create('activerecorddb')); + + // Compression middleware must be the last in the chain, just before the ETag, if present. //FMVC.AddMiddleware(TMVCCompressionMiddleware.Create); - + // ETag middleware must be the latest in the chain //FMVC.AddMiddleware(TMVCETagMiddleware.Create); - - + + end; procedure TMyWebModule.WebModuleDestroy(Sender: TObject); diff --git a/samples/avoid_mid_air_collisions_sample/avoid_mid_air_collisions_sample.dpr b/samples/avoid_mid_air_collisions_sample/avoid_mid_air_collisions_sample.dpr index 42ebde84..fd354656 100644 --- a/samples/avoid_mid_air_collisions_sample/avoid_mid_air_collisions_sample.dpr +++ b/samples/avoid_mid_air_collisions_sample/avoid_mid_air_collisions_sample.dpr @@ -13,10 +13,32 @@ uses Web.WebReq, Web.WebBroker, IdContext, + FireDAC.Stan.Intf, + FireDAC.Stan.Option, + FireDAC.Stan.Error, + FireDAC.UI.Intf, + FireDAC.Phys.Intf, + FireDAC.Stan.Def, + FireDAC.Stan.Pool, + FireDAC.Stan.Async, + FireDAC.Phys, + FireDAC.Phys.MySQL, + FireDAC.Phys.MySQLDef, + FireDAC.VCLUI.Wait, + Data.DB, + FireDAC.Comp.Client, + FireDAC.Stan.Param, + FireDAC.DatS, + FireDAC.DApt.Intf, + FireDAC.DApt, + FireDAC.Comp.DataSet, + MVCFramework.SQLGenerators.PostgreSQL, IdHTTPWebBrokerBridge, MainControllerU in 'MainControllerU.pas', WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule}, - MVCFramework.Utils in '..\..\sources\MVCFramework.Utils.pas'; + MVCFramework.Utils in '..\..\sources\MVCFramework.Utils.pas', + Entities in '..\activerecord_restful_crud\Entities.pas', + MVCFramework.ActiveRecord; {$R *.res} @@ -53,10 +75,46 @@ end; procedure LoadFakeData; begin - TMVCCacheSingleton.Instance.SetValue('1', TPerson.GetNew(1, 'Daniele','Teti')); - TMVCCacheSingleton.Instance.SetValue('2', TPerson.GetNew(2, 'Peter','Parker')); - TMVCCacheSingleton.Instance.SetValue('3', TPerson.GetNew(3, 'Bruce','Banner')); - TMVCCacheSingleton.Instance.SetValue('4', TPerson.GetNew(4, 'Sue','Storm')); + ActiveRecordConnectionsRegistry.AddDefaultConnection('activerecorddb'); + try + TMVCActiveRecord.DeleteAll(TPerson); + + with TPerson.Create do + try + FirstName := 'Daniele'; + LastName := 'Teti'; + DOB := nil; + IsMale := True; + Insert; + finally + Free; + end; + + with TPerson.Create do + try + FirstName := 'Peter'; + LastName := 'Parker'; + DOB := EncodeDate(1960,10,11); + IsMale := True; + Insert; + finally + Free; + end; + + with TPerson.Create do + try + FirstName := 'Sue'; + LastName := 'Storm'; + DOB := EncodeDate(1970,2,11); + IsMale := False; + Insert; + finally + Free; + end; + + finally + ActiveRecordConnectionsRegistry.RemoveDefaultConnection(); + end; end; begin diff --git a/samples/avoid_mid_air_collisions_sample/avoid_mid_air_collisions_sample.dproj b/samples/avoid_mid_air_collisions_sample/avoid_mid_air_collisions_sample.dproj index a2a7849b..f41d734a 100644 --- a/samples/avoid_mid_air_collisions_sample/avoid_mid_air_collisions_sample.dproj +++ b/samples/avoid_mid_air_collisions_sample/avoid_mid_air_collisions_sample.dproj @@ -1,7 +1,7 @@  {03D8066E-D767-4E59-8D05-7C3341BECDFC} - 19.4 + 19.5 None True Debug @@ -126,6 +126,7 @@ TWebModule + Base @@ -153,7 +154,7 @@ Embarcadero C++Builder Office XP Servers Package - + true @@ -516,7 +517,7 @@ 1 .dylib - + 1 .dylib @@ -550,7 +551,7 @@ 0 - + 0 @@ -571,13 +572,17 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -587,7 +592,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -597,7 +602,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -607,7 +612,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -617,7 +622,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -627,7 +632,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -637,7 +642,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -647,7 +652,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -657,7 +662,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -667,7 +672,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -677,7 +682,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -687,7 +692,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -697,7 +702,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -707,7 +712,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -717,7 +722,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -727,7 +732,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -737,7 +742,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -747,7 +752,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -757,7 +762,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -779,6 +784,10 @@ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1 + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + @@ -790,7 +799,7 @@ 1 - + 1 @@ -826,7 +835,7 @@ 1 - + 1 @@ -883,6 +892,7 @@ + diff --git a/samples/middleware_activerecord/MainControllerU.pas b/samples/middleware_activerecord/MainControllerU.pas index 017805da..0130549d 100644 --- a/samples/middleware_activerecord/MainControllerU.pas +++ b/samples/middleware_activerecord/MainControllerU.pas @@ -27,8 +27,8 @@ uses procedure TMyController.Index; begin Render(ObjectDict().Add('people', - TMVCActiveRecord.SelectRQL('and(gt(id, 2),lt(id,6))', 100) - //TMVCActiveRecord.All + //TMVCActiveRecord.SelectRQL('and(gt(id, 2),lt(id,6))', 100) + TMVCActiveRecord.SelectRQL('sort(+personSurname)', 10) )); end; diff --git a/samples/middleware_activerecord/middleware_activerecord.dproj b/samples/middleware_activerecord/middleware_activerecord.dproj index 5bb434d9..01badd12 100644 --- a/samples/middleware_activerecord/middleware_activerecord.dproj +++ b/samples/middleware_activerecord/middleware_activerecord.dproj @@ -1,7 +1,7 @@  {0BE611DE-35B1-4B03-8B00-181E5DBFFF4A} - 19.4 + 19.5 None True Debug @@ -153,7 +153,7 @@ Embarcadero C++Builder Office XP Servers Package - + true @@ -169,12 +169,7 @@ true - - - middleware_activerecord.exe - true - - + 1 @@ -516,7 +511,7 @@ 1 .dylib - + 1 .dylib @@ -550,7 +545,7 @@ 0 - + 0 @@ -571,13 +566,17 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -587,7 +586,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -597,7 +596,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -607,7 +606,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -617,7 +616,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -627,7 +626,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -637,7 +636,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -647,7 +646,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -657,7 +656,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -667,7 +666,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -677,7 +676,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -687,7 +686,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -697,7 +696,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -707,7 +706,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -717,7 +716,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -727,7 +726,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -737,7 +736,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -747,7 +746,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -757,7 +756,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -779,6 +778,10 @@ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1 + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + @@ -790,7 +793,7 @@ 1 - + 1 @@ -826,7 +829,7 @@ 1 - + 1 @@ -883,6 +886,7 @@ + diff --git a/samples/renders/renders.dproj b/samples/renders/renders.dproj index a89dbcd8..64c973ee 100644 --- a/samples/renders/renders.dproj +++ b/samples/renders/renders.dproj @@ -1,7 +1,7 @@  {8CCDACDA-3FA5-486E-AD8E-63E4113177EE} - 19.4 + 19.5 None renders.dpr True @@ -214,55 +214,28 @@ Microsoft Office XP Sample Automation Server Wrapper Components - + true - - - true - - true - - - true - - + + true - - - true - - - - - renders.exe - true - - - - - renders.exe - true - - - - - renders - true - - + + + + 1 @@ -281,16 +254,6 @@ 64 - - - classes - 1 - - - classes - 1 - - res\xml @@ -333,7 +296,6 @@ 1 - library\lib\armeabi-v7a @@ -615,7 +577,7 @@ 1 .dylib - + 1 .dylib @@ -649,7 +611,7 @@ 0 - + 0 @@ -670,13 +632,17 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -686,181 +652,27 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -870,7 +682,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -880,7 +692,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -890,7 +702,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -900,7 +712,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -910,191 +722,37 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1104,7 +762,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1114,7 +772,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1124,7 +782,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1134,7 +792,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1144,7 +802,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1154,7 +812,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1164,7 +822,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1186,8 +844,11 @@ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1 + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + - @@ -1198,7 +859,7 @@ 1 - + 1 @@ -1234,7 +895,7 @@ 1 - + 1 @@ -1291,6 +952,7 @@ + diff --git a/sources/MVCFramework.Commons.pas b/sources/MVCFramework.Commons.pas index b5aea1dc..f172fbc0 100644 --- a/sources/MVCFramework.Commons.pas +++ b/sources/MVCFramework.Commons.pas @@ -352,6 +352,11 @@ type /// request MUST NOT be repeated until it is requested by a separate user action. /// InsufficientStorage = 507; + + /// + /// Returns standard ReasonString for a given HTTP status code + /// + class function ReasonStringFor(const HTTPStatusCode: Integer): String; static; end; EMVCException = class(Exception) @@ -608,6 +613,11 @@ type {$SCOPEDENUMS ON} TMVCCompressionType = (ctNone, ctDeflate, ctGZIP); + TMVCHTTPStatusCode = record + Code: Integer; + ReasonString: String; + end; + { GENERIC TYPE ALIASES } TMVCListOfString = TList; @@ -677,6 +687,71 @@ const ('224.0.0.0', '239.255.255.255'), ('240.0.0.0', '255.255.255.255')); + +const + MVC_HTTP_STATUS_CODES: array [0..57] of TMVCHTTPStatusCode = + ( + (Code: 100; ReasonString: 'Continue'), + (Code: 101; ReasonString: 'Switching Protocols'), + (Code: 102; ReasonString: 'Processing'), + (Code: 200; ReasonString: 'OK'), + (Code: 201; ReasonString: 'Created'), + (Code: 202; ReasonString: 'Accepted'), + (Code: 203; ReasonString: 'Non-Authoritative Information'), + (Code: 204; ReasonString: 'No Content'), + (Code: 205; ReasonString: 'Reset Content'), + (Code: 206; ReasonString: 'Partial Content'), + (Code: 207; ReasonString: 'Multi-Status'), + (Code: 208; ReasonString: 'Already Reported'), + (Code: 226; ReasonString: 'IM Used'), + (Code: 300; ReasonString: 'Multiple Choices'), + (Code: 301; ReasonString: 'Moved Permanently'), + (Code: 302; ReasonString: 'Found'), + (Code: 303; ReasonString: 'See Other'), + (Code: 304; ReasonString: 'Not Modified'), + (Code: 305; ReasonString: 'Use Proxy'), + (Code: 306; ReasonString: 'Reserved'), + (Code: 307; ReasonString: 'Temporary Redirect'), + (Code: 308; ReasonString: 'Permanent Redirect'), + (Code: 400; ReasonString: 'Bad Request'), + (Code: 401; ReasonString: 'Unauthorized'), + (Code: 402; ReasonString: 'Payment Required'), + (Code: 403; ReasonString: 'Forbidden'), + (Code: 404; ReasonString: 'Not Found'), + (Code: 405; ReasonString: 'Method Not Allowed'), + (Code: 406; ReasonString: 'Not Acceptable'), + (Code: 407; ReasonString: 'Proxy Authentication Required'), + (Code: 408; ReasonString: 'Request Timeout'), + (Code: 409; ReasonString: 'Conflict'), + (Code: 410; ReasonString: 'Gone'), + (Code: 411; ReasonString: 'Length Required'), + (Code: 412; ReasonString: 'Precondition Failed'), + (Code: 413; ReasonString: 'Request Entity Too Large'), + (Code: 414; ReasonString: 'Request-URI Too Long'), + (Code: 415; ReasonString: 'Unsupported Media Type'), + (Code: 416; ReasonString: 'Requested Range Not Satisfiable'), + (Code: 417; ReasonString: 'Expectation Failed'), + (Code: 422; ReasonString: 'Unprocessable Entity'), + (Code: 423; ReasonString: 'Locked'), + (Code: 424; ReasonString: 'Failed Dependency'), + (Code: 426; ReasonString: 'Upgrade Required'), + (Code: 428; ReasonString: 'Precondition Required'), + (Code: 429; ReasonString: 'Too Many Requests'), + (Code: 431; ReasonString: 'Request Header Fields Too Large'), + (Code: 500; ReasonString: 'Internal Server Error'), + (Code: 501; ReasonString: 'Not Implemented'), + (Code: 502; ReasonString: 'Bad Gateway'), + (Code: 503; ReasonString: 'Service Unavailable'), + (Code: 504; ReasonString: 'Gateway Timeout'), + (Code: 505; ReasonString: 'HTTP Version Not Supported'), + (Code: 506; ReasonString: 'Variant Also Negotiates (Experimental)'), + (Code: 507; ReasonString: 'Insufficient Storage'), + (Code: 508; ReasonString: 'Loop Detected'), + (Code: 510; ReasonString: 'Not Extended'), + (Code: 511; ReasonString: 'Network Authentication Required') + ); + + type TMVCParseAuthentication = class public @@ -1616,6 +1691,27 @@ begin end; +function ReasonStringByHTTPStatusCode(const HTTPStatusCode: Integer): String; +var + I: Integer; +begin + for I := Low(MVC_HTTP_STATUS_CODES) to High(MVC_HTTP_STATUS_CODES) do + begin + if MVC_HTTP_STATUS_CODES[I].Code = HTTPStatusCode then + begin + Exit(MVC_HTTP_STATUS_CODES[I].ReasonString); + end; + end; + raise EMVCException.Create('Invalid HTTP status code: ' + IntToStr(HTTPStatusCode)); +end; + +{ HTTP_STATUS } + +class function HTTP_STATUS.ReasonStringFor(const HTTPStatusCode: Integer): String; +begin + Result := ReasonStringByHTTPStatusCode(HTTPStatusCode); +end; + initialization gLock := TObject.Create; diff --git a/sources/MVCFramework.Middleware.ActiveRecord.pas b/sources/MVCFramework.Middleware.ActiveRecord.pas index 87e4b439..6e1eb20e 100644 --- a/sources/MVCFramework.Middleware.ActiveRecord.pas +++ b/sources/MVCFramework.Middleware.ActiveRecord.pas @@ -112,7 +112,10 @@ begin begin FDManager.ConnectionDefFileAutoLoad := False; FDManager.ConnectionDefFileName := fConnectionDefFileName; - FDManager.LoadConnectionDefFile; + if not FDManager.ConnectionDefFileLoaded then + begin + FDManager.LoadConnectionDefFile; + end; if not FDManager.IsConnectionDef(fConnectionDefName) then begin raise EMVCConfigException.CreateFmt('ConnectionDefName "%s" not found in config file "%s"', diff --git a/sources/MVCFramework.Serializer.JsonDataObjects.pas b/sources/MVCFramework.Serializer.JsonDataObjects.pas index 1394aeb5..ac232e70 100644 --- a/sources/MVCFramework.Serializer.JsonDataObjects.pas +++ b/sources/MVCFramework.Serializer.JsonDataObjects.pas @@ -1391,14 +1391,21 @@ begin if lOwnedAttribute.ClassRef <> nil then begin ChildObject := TMVCSerializerHelper.CreateObject(lOwnedAttribute.ClassRef.QualifiedClassName); + AValue := ChildObject; //dt20221006 end else begin case AType of stUnknown, stDefault, stProperties: + begin ChildObject := TMVCSerializerHelper.CreateObject(TRttiProperty(ARttiMember).PropertyType); + AValue := ChildObject; //dt20221006 + end; stFields: + begin ChildObject := TMVCSerializerHelper.CreateObject(TRttiField(ARttiMember).FieldType); + AValue := ChildObject; //dt20221006 + end; end; end; lTypeInfo := ChildObject.ClassInfo; diff --git a/sources/MVCFramework.Utils.pas b/sources/MVCFramework.Utils.pas index 3597016f..26cd0c00 100644 --- a/sources/MVCFramework.Utils.pas +++ b/sources/MVCFramework.Utils.pas @@ -24,6 +24,8 @@ unit MVCFramework.Utils; +{$I dmvcframework.inc} + interface uses @@ -37,6 +39,8 @@ function StrToJSONArray(const aString: String; ARaiseExceptionOnError: Boolean = function WrapAsList(const AObject: TObject; AOwnsObject: Boolean = False): IMVCList; function GetMD5HashFromStream(AStream: TStream): string; function GetMD5HashFromString(const AString: String): string; +function GetSHA1HashFromString(const AString: String): string; +function GetSHA1HashFromStream(AStream: TStream): string; implementation @@ -45,6 +49,7 @@ uses System.Hash, {$ELSE} IdHashMessageDigest, + IdHashSHA, {$ENDIF} MVCFramework.Serializer.JsonDataObjects, MVCFramework.Commons, @@ -69,6 +74,24 @@ begin {$ENDIF} end; +function GetSHA1HashFromStream(AStream: TStream): string; +{$IF not defined(TOKYOORBETTER)} +var + lSHA1Hash: TIdHashSHA1; +{$ENDIF} +begin +{$IF defined(TOKYOORBETTER)} + Result := THashSHA1.GetHashString(AStream); +{$ELSE} + lSHA1Hash := TIdHashSHA1.Create; + try + Result := lSHA1Hash.HashStreamAsHex(AStream); + finally + lSHA1Hash.Free; + end; +{$ENDIF} +end; + function GetMD5HashFromString(const AString: String): string; {$IF not defined(TOKYOORBETTER)} var @@ -76,7 +99,7 @@ var {$ENDIF} begin {$IF defined(TOKYOORBETTER)} - Result := THashMD5.GetHashString(AStream); + Result := THashMD5.GetHashString(AString); {$ELSE} lMD5Hash := TIdHashMessageDigest5.Create; try @@ -87,6 +110,24 @@ begin {$ENDIF} end; +function GetSHA1HashFromString(const AString: String): string; +{$IF not defined(TOKYOORBETTER)} +var + lSHA1Hash: TIdHashSHA1; +{$ENDIF} +begin +{$IF defined(TOKYOORBETTER)} + Result := THashSHA1.GetHashString(AString); +{$ELSE} + lSHA1Hash := TIdHashSHA1.Create; + try + Result := lSHA1Hash.HashStringAsHex(AString); + finally + lSHA1Hash.Free; + end; +{$ENDIF} +end; + function NewJSONSerializer: IMVCJSONSerializer; begin diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index 9eb118d9..18be3521 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -681,7 +681,7 @@ type /// https://restfulapi.net/http-status-201-created/ /// procedure Render201Created(const Location: string = ''; - const Reason: string = 'Created'); virtual; + const Reason: string = ''); virtual; /// /// Allow a server to accept a request for some other process (perhaps a batch-oriented process that is only run once per day) without requiring that the user agent’s connection to the server persist until the process is completed. /// The entity returned with this response SHOULD describe the request’s current status and point to (or embed) a status monitor that can provide the user with (or without) an estimate of when the request will be fulfilled. @@ -696,7 +696,7 @@ type /// The 204 response MUST NOT include a message-body and thus is always terminated by the first empty line after the header fields. /// procedure Render204NoContent(const Location: string = ''; - const Reason: string = 'No Content'); virtual; + const Reason: string = ''); virtual; function Serializer: IMVCSerializer; overload; function Serializer(const AContentType: string; const ARaiseExceptionIfNotExists: Boolean = True): IMVCSerializer; overload; @@ -811,6 +811,7 @@ type // Avoiding mid-air collisions - support procedure SetETag(const Data: String); + function GetIfMatch(): String; procedure CheckIfMatch(const Data: String); // END - Avoiding mid-air collisions - support @@ -1048,6 +1049,7 @@ type public constructor Create; overload; virtual; constructor Create(AStatusCode: Integer; AReasonString: string; AMessage: string); overload; + destructor Destroy; override; property StatusCode: Integer read FStatusCode write FStatusCode; property ReasonString: string read FReasonString write FReasonString; property Message: string read FMessage write FMessage; @@ -1072,6 +1074,8 @@ type property Items: TObjectList read FItems; end; + + TMVCBaseViewEngine = class(TMVCBase) private FViewName: string; @@ -3386,13 +3390,13 @@ begin end; // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag#avoiding_mid-air_collisions - lReqETag := Context.Request.GetHeader('If-Match'); + lReqETag := GetIfMatch; if lReqETag.IsEmpty then begin raise EMVCException.Create(HTTP_STATUS.PreconditionFailed, 'If-Match header is empty'); end; - if lReqETag <> GetMD5HashFromString(Data) then + if lReqETag <> GetSHA1HashFromString(Data) then begin raise EMVCException.Create(HTTP_STATUS.PreconditionFailed, 'mid-air collisions detected, cannot update or delete resource.'); end; @@ -3452,6 +3456,11 @@ begin Result := Engine.WebModule; end; +function TMVCController.GetIfMatch: String; +begin + Result := Context.Request.GetHeader('If-Match'); +end; + function TMVCController.GetSession: TWebSession; begin Result := GetContext.Session; @@ -3635,7 +3644,10 @@ end; procedure TMVCRenderer.ResponseStatus(const AStatusCode: Integer; const AReasonString: string); begin SetStatusCode(AStatusCode); - GetContext.Response.ReasonString := AReasonString; + if AReasonString = '' then + GetContext.Response.ReasonString := HTTP_STATUS.ReasonStringFor(AStatusCode) + else + GetContext.Response.ReasonString := AReasonString; end; function TMVCRenderer.ResponseStream: TStringBuilder; @@ -3730,7 +3742,7 @@ end; procedure TMVCController.SetETag(const Data: String); begin - Context.Response.SetCustomHeader('ETag', GetMD5HashFromString(Data)); + Context.Response.SetCustomHeader('ETag', GetSHA1HashFromString(Data)); end; procedure TMVCController.SetViewData(const aModelName: string; const Value: TObject); @@ -3763,18 +3775,18 @@ begin SendStream(AStream, AOwns); end; -procedure TMVCRenderer.Render(const AErrorCode: Integer; -const AErrorMessage, AErrorClassName: string; const ADataObject: TObject); -var R: TMVCErrorResponse; +procedure TMVCRenderer.Render( + const AErrorCode: Integer; + const AErrorMessage, AErrorClassName: string; + const ADataObject: TObject); +var + R: TMVCErrorResponse; begin ResponseStatus(AErrorCode, AErrorMessage); R := TMVCErrorResponse.Create; try R.StatusCode := AErrorCode; - if ((R.StatusCode div 100) = 2) then - R.ReasonString := 'ok' - else - R.ReasonString := 'error'; + R.ReasonString := HTTP_STATUS.ReasonStringFor(AErrorCode); R.Message := AErrorMessage; R.Classname := AErrorClassName; R.Data := ADataObject; @@ -4041,7 +4053,7 @@ begin R := TMVCErrorResponse.Create; try R.StatusCode := GetContext.Response.StatusCode; - R.ReasonString := 'error'; + R.ReasonString := HTTP_STATUS.ReasonStringFor(R.StatusCode); R.Message := AException.Message; R.Classname := AException.Classname; if AException is EMVCException then @@ -4087,6 +4099,7 @@ begin begin try GetContext.Response.StatusCode := AResponse.StatusCode; + GetContext.Response.ReasonString := HTTP_STATUS.ReasonStringFor(AResponse.StatusCode); Render(AResponse, False, stProperties); finally if AOwns then @@ -4136,6 +4149,7 @@ end; constructor TMVCResponse.Create; begin inherited Create; + fDataObject := nil; end; constructor TMVCErrorResponse.Create; @@ -4152,6 +4166,12 @@ begin message := AMessage; end; +destructor TMVCResponse.Destroy; +begin + fDataObject.Free; + inherited; +end; + destructor TMVCErrorResponse.Destroy; begin FItems.Free; diff --git a/unittests/general/Several/BOs.pas b/unittests/general/Several/BOs.pas index b2cd09b0..e23f1bc2 100644 --- a/unittests/general/Several/BOs.pas +++ b/unittests/general/Several/BOs.pas @@ -120,7 +120,7 @@ type [MVCTableField('creation_date')] fCreationDate: NullableTDate; public - procedure Assign(Customer: TCustomer); overload; + procedure Assign(Customer: TCustomer); reintroduce; overload; function Clone: TCustomer; function ToString: String; override; property ID: NullableInt32 read fID write fID; diff --git a/unittests/general/Several/DMVCFrameworkTests.dproj b/unittests/general/Several/DMVCFrameworkTests.dproj index 98aa86c0..33c6749e 100644 --- a/unittests/general/Several/DMVCFrameworkTests.dproj +++ b/unittests/general/Several/DMVCFrameworkTests.dproj @@ -1,7 +1,7 @@  {0582DE6A-D716-46D3-8CBD-84AD73A4B536} - 19.4 + 19.5 VCL True TESTINSIGHT @@ -323,65 +323,17 @@ Microsoft Office XP Sample Automation Server Wrapper Components - - - - true - - - - - true - - - - - DMVCFrameworkTests.exe - true - - - - - DMVCFrameworkTests.exe - true - - - - - DMVCFrameworkTests.exe - true - - - - - DMVCFrameworkTests.rsm - true - - - - - DMVCFrameworkTests.rsm - true - - - - - DMVCFrameworkTests.rsm - true - - - - - DMVCFrameworkTests.exe - true - - - - - DMVCFrameworkTests.rsm - true - - + + + + + + + + + + + 1 @@ -400,16 +352,6 @@ 64 - - - classes - 1 - - - classes - 1 - - res\xml @@ -452,12 +394,6 @@ 1 - - - library\lib\x86 - 1 - - library\lib\armeabi-v7a @@ -739,7 +675,7 @@ 1 .dylib - + 1 .dylib @@ -773,7 +709,7 @@ 0 - + 0 @@ -794,13 +730,17 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -810,169 +750,27 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -982,7 +780,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -992,7 +790,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1002,7 +800,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1012,7 +810,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1022,191 +820,37 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1216,7 +860,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1226,7 +870,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1236,7 +880,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1246,7 +890,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1256,7 +900,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1266,7 +910,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1276,7 +920,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1298,9 +942,11 @@ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1 + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + - - @@ -1311,11 +957,10 @@ 1 - + 1 - @@ -1348,7 +993,7 @@ 1 - + 1 @@ -1406,6 +1051,7 @@ + diff --git a/unittests/general/Several/LiveServerTestU.pas b/unittests/general/Several/LiveServerTestU.pas index bf8465c9..fa378839 100644 --- a/unittests/general/Several/LiveServerTestU.pas +++ b/unittests/general/Several/LiveServerTestU.pas @@ -983,7 +983,7 @@ begin Assert.areEqual('message', lJSON.S['message'], lJSON.ToJSON()); Assert.areEqual('EMVCException', lJSON.S['classname'], lJSON.ToJSON()); Assert.areEqual(500, lJSON.I['statuscode'], lJSON.ToJSON()); - Assert.areEqual('error', lJSON.S['reasonstring'], lJSON.ToJSON()); + Assert.areEqual('Internal Server Error', lJSON.S['reasonstring'], lJSON.ToJSON()); Assert.areEqual(0, lJSON.A['items'].Count, lJSON.ToJSON()); Assert.isTrue(lJSON.IsNull('data'), lJSON.ToJSON()); finally @@ -1004,7 +1004,7 @@ begin Assert.areEqual('message', lJSON.S['message'], lJSON.ToJSON()); Assert.areEqual('EMVCException', lJSON.S['classname'], lJSON.ToJSON()); Assert.areEqual(HTTP_STATUS.BadRequest, lJSON.I['statuscode'], lJSON.ToJSON()); - Assert.areEqual('error', lJSON.S['reasonstring'], lJSON.ToJSON()); + Assert.areEqual('Bad Request', lJSON.S['reasonstring'], lJSON.ToJSON()); Assert.areEqual(0, lJSON.A['items'].Count, lJSON.ToJSON()); Assert.isTrue(lJSON.IsNull('data'), lJSON.ToJSON()); finally @@ -1024,7 +1024,7 @@ begin Assert.areEqual('message', lJSON.S['message'], lJSON.ToJSON()); Assert.areEqual('EMVCException', lJSON.S['classname'], lJSON.ToJSON()); Assert.areEqual(HTTP_STATUS.Created, lJSON.I['statuscode'], lJSON.ToJSON()); - Assert.areEqual('error', lJSON.S['reasonstring'], lJSON.ToJSON()); + Assert.areEqual('Created', lJSON.S['reasonstring'], lJSON.ToJSON()); Assert.areEqual(999, lJSON.I['apperrorcode'], lJSON.ToJSON()); Assert.areEqual(0, lJSON.A['items'].Count, lJSON.ToJSON()); Assert.isTrue(lJSON.IsNull('data'), lJSON.ToJSON()); @@ -1046,7 +1046,7 @@ begin Assert.areEqual('detailedmessage', lJSON.S['detailedmessage'], lJSON.ToJSON()); Assert.areEqual('EMVCException', lJSON.S['classname'], lJSON.ToJSON()); Assert.areEqual(HTTP_STATUS.Created, lJSON.I['statuscode'], lJSON.ToJSON()); - Assert.areEqual('error', lJSON.S['reasonstring'], lJSON.ToJSON()); + Assert.areEqual('Created', lJSON.S['reasonstring'], lJSON.ToJSON()); Assert.areEqual(999, lJSON.I['apperrorcode'], lJSON.ToJSON()); Assert.areEqual(2, lJSON.A['items'].Count, lJSON.ToJSON()); Assert.areEqual('erritem1', lJSON.A['items'].O[0].S['message'], lJSON.ToJSON()); diff --git a/unittests/general/TestServer/TestServer.dproj b/unittests/general/TestServer/TestServer.dproj index 5db91cfe..000e11ab 100644 --- a/unittests/general/TestServer/TestServer.dproj +++ b/unittests/general/TestServer/TestServer.dproj @@ -7,7 +7,7 @@ 129 Console None - 19.4 + 19.5 Win32 @@ -154,7 +154,7 @@ True False - + true @@ -182,12 +182,7 @@ true - - - TestServer.exe - true - - + .\www @@ -202,12 +197,7 @@ true - - - TestServer - true - - + 1 @@ -226,16 +216,6 @@ 64 - - - classes - 1 - - - classes - 1 - - res\xml @@ -559,7 +539,7 @@ 1 .dylib - + 1 .dylib @@ -593,7 +573,7 @@ 0 - + 0 @@ -614,13 +594,17 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -630,137 +614,27 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -770,7 +644,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -780,7 +654,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -790,7 +664,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -800,7 +674,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -810,191 +684,37 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1004,7 +724,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1 @@ -1014,7 +734,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1024,7 +744,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1034,7 +754,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1044,7 +764,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1054,7 +774,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1064,7 +784,7 @@ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 - + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1 @@ -1086,8 +806,11 @@ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1 + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + - @@ -1098,7 +821,7 @@ 1 - + 1 @@ -1134,7 +857,7 @@ 1 - + 1 @@ -1191,6 +914,7 @@ +