From cae4396c186d47738de3db38f50bed7f392dda57 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Sun, 5 Feb 2023 00:36:01 +0100 Subject: [PATCH 01/31] Works: PODO, TObjectList, TStream, string, enum, bool, nested objects --- sources/MVCFramework.Commons.pas | 57 + sources/MVCFramework.Router.pas | 4 +- sources/MVCFramework.pas | 60 +- sources/dmvcframeworkbuildconsts.inc | 2 +- unittests/general/Several/FrameworkTestsU.pas | 49 - .../TestServer/TestServerControllerU.pas | 124 +- .../general/TestServer/WebModuleUnit.pas | 1 + .../dmvcframework_nunit_win64.xml | 1746 ++++++++--------- 8 files changed, 1110 insertions(+), 933 deletions(-) diff --git a/sources/MVCFramework.Commons.pas b/sources/MVCFramework.Commons.pas index 2b13e2f4..c7577aba 100644 --- a/sources/MVCFramework.Commons.pas +++ b/sources/MVCFramework.Commons.pas @@ -621,6 +621,27 @@ type ReasonString: String; end; + { TMVCActionResult hierarchy} + IMVCActionResult = interface + ['{9FEDD192-C050-4123-B361-E88C13121928}'] + function GetStatusCode: UInt16; + function HasBody: Boolean; + function GetData: TObject; + end; + TMVCActionResult = class(TInterfacedObject, IMVCActionResult) + protected + fStatusCode: UInt16; + fData: TObject; + function GetStatusCode: UInt16; + function HasBody: Boolean; + function GetData: TObject; + public + constructor Create(const StatusCode: UInt16); overload; + constructor Create(const StatusCode: UInt16; const Data: TObject); overload; + destructor Destroy; override; + // properties + end; + { TMVCActionResult hierarchy -- end} { GENERIC TYPE ALIASES } TMVCListOfString = TList; @@ -1737,6 +1758,42 @@ begin Result := ReasonStringByHTTPStatusCode(HTTPStatusCode); end; +{ TMVCActionResult } + +constructor TMVCActionResult.Create(const StatusCode: UInt16); +begin + Create(StatusCode, nil); +end; + +constructor TMVCActionResult.Create(const StatusCode: UInt16; + const Data: TObject); +begin + inherited Create; + fStatusCode := StatusCode; + fData := Data; +end; + +destructor TMVCActionResult.Destroy; +begin + fData.Free; + inherited; +end; + +function TMVCActionResult.GetData: TObject; +begin + Result := fData; +end; + +function TMVCActionResult.HasBody: Boolean; +begin + Result := fData <> nil; +end; + +function TMVCActionResult.GetStatusCode: UInt16; +begin + Result := fStatusCode; +end; + initialization gLock := TObject.Create; diff --git a/sources/MVCFramework.Router.pas b/sources/MVCFramework.Router.pas index 0681944b..2ed2477c 100644 --- a/sources/MVCFramework.Router.pas +++ b/sources/MVCFramework.Router.pas @@ -1,4 +1,4 @@ -// *************************************************************************** +// *************************************************************************** // // Delphi MVC Framework // @@ -237,7 +237,7 @@ begin begin if LMethod.Visibility <> mvPublic then // 2020-08-08 Continue; - if (LMethod.MethodKind <> mkProcedure) { or LMethod.IsClassMethod } then + if not (LMethod.MethodKind in [mkProcedure, mkFunction]) then Continue; LAttributes := LMethod.GetAttributes; diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index d57b2a90..8ab51afa 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -2393,7 +2393,9 @@ var lSelectedController: TMVCController; lActionFormalParams: TArray; lActualParams: TArray; - lBodyParameter: TObject; + lBodyParameter, lResponseObject: TObject; + lInvokeResult: TValue; + lObjList: IMVCList; begin Result := False; @@ -2494,7 +2496,56 @@ begin if not lHandled then begin try - lRouter.MethodToCall.Invoke(lSelectedController, lActualParams); + if lRouter.MethodToCall.MethodKind = mkProcedure then + begin + lRouter.MethodToCall.Invoke(lSelectedController, lActualParams); + end + else + begin + lInvokeResult := lRouter.MethodToCall.Invoke(lSelectedController, lActualParams); + case lInvokeResult.Kind of + tkClass: + begin + lResponseObject := lInvokeResult.AsObject; + try + // https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0 + if lResponseObject is TStream then + begin + lContext.Response.RawWebResponse.Content := EmptyStr; + lContext.Response.RawWebResponse.ContentType := lContext.Response.ContentType; + lContext.Response.RawWebResponse.ContentStream := TStream(lResponseObject); + lContext.Response.RawWebResponse.FreeContentStream := True; + lResponseObject := nil; //do not free it!! + end + else + begin + if TDuckTypedList.CanBeWrappedAsList(lResponseObject, lObjList) then + begin + lSelectedController.Render(lObjList); + end + else + begin + lSelectedController.Render(lResponseObject, False); + end; + end; + finally + lResponseObject.Free; + end + end; + tkUString, tkString: + begin + lSelectedController.Render(lInvokeResult.AsString); + end; + tkEnumeration: + begin + lSelectedController.Render(GetEnumName(lInvokeResult.TypeInfo, lInvokeResult.AsOrdinal)); + end + else + begin + RaiseSerializationError('Cannot serialize type ' + lInvokeResult.TypeInfo.Name); + end; + end; + end; finally lSelectedController.OnAfterAction(lContext, lRouterMethodToCallName); end; @@ -3724,8 +3775,9 @@ begin GetContext.Response.RawWebResponse.FreeContentStream := True; end; -function TMVCRenderer.Serializer(const AContentType: string; -const ARaiseExceptionIfNotExists: Boolean): IMVCSerializer; +function TMVCRenderer.Serializer( + const AContentType: string; + const ARaiseExceptionIfNotExists: Boolean): IMVCSerializer; var lContentMediaType: string; lContentCharSet: string; begin diff --git a/sources/dmvcframeworkbuildconsts.inc b/sources/dmvcframeworkbuildconsts.inc index ee6819b3..169d4fef 100644 --- a/sources/dmvcframeworkbuildconsts.inc +++ b/sources/dmvcframeworkbuildconsts.inc @@ -1,2 +1,2 @@ const - DMVCFRAMEWORK_VERSION = '3.2.3-radium'; \ No newline at end of file + DMVCFRAMEWORK_VERSION = '3.3.0-fluorine-beta'; \ No newline at end of file diff --git a/unittests/general/Several/FrameworkTestsU.pas b/unittests/general/Several/FrameworkTestsU.pas index 982d8d50..65f63fb1 100644 --- a/unittests/general/Several/FrameworkTestsU.pas +++ b/unittests/general/Several/FrameworkTestsU.pas @@ -38,43 +38,6 @@ uses type - [TestFixture] - TTestMappers = class(TObject) - protected - [Test] - procedure SameFishesDataSet(ds, ds2: TDataSet); - - public - // procedure TestObjectToJSONObject; - // procedure TestObjectListToJSONArray; - // procedure TestObjectToJSONObject_Generics; - // procedure TestWrappedListToJSONArray; - // procedure TestJSONObjectToObjectAndBack; - // procedure TestLoadJSONObjectToObjectAndBack; - // procedure TestSerializeUsingProperties; - // procedure TestSerializeUsingFields; - // procedure TestSerializeUsingFieldsComplexObject; - // procedure TestSerializeUsingFieldsComplexObject2; - // procedure TestSerializeUsingFieldsWithNotExixtentPropetyInJSONObject; - // procedure TestComplexObjectToJSONObjectAndBack; - // procedure TestComplexObjectToJSONObjectAndBackWithNilReference; - // procedure TestDataSetToJSONObject; - // procedure TestDataSetToJSONObjectWithNulls; - // procedure TestDataSetToJSONObjectFieldPolicyLowerCase; - // procedure TestDataSetToJSONObjectFieldPolicyUpperCase; - // procedure TestDataSetToJSONObjectFieldPolicyAsIsCase; - // procedure TestDataSetToJSONArray; - // procedure TestObjectToJSONObjectAndBackWithStringStreamUTF16; - // procedure TestObjectToJSONObjectAndBackWithStringStreamUTF8; - // procedure TestObjectToJSONObjectAndBackWithStream; - // procedure TestJSONArrayToObjectListNoGenerics; - // procedure TestJSONArrayToObjectListNoGenericsWrappedList; - // procedure TestCheckMapperSerializeAsStringIsEmptyStrIfObjIsNil; - // procedure TestJSONObjectToObjectWithNullInJSONString; - // procedure TestJSONObjectStringToObject; - // procedure TestJSONObjectStringToObjectWithWrongJSON; - end; - [TestFixture] TTestRouting = class(TObject) private @@ -352,18 +315,6 @@ begin end; end; -procedure TTestMappers.SameFishesDataSet(ds, ds2: TDataSet); -begin - Assert.areEqual(ds.FieldByName('Species No').AsInteger, ds2.FieldByName('Species No').AsInteger); - Assert.areEqual(ds.FieldByName('Category').AsString, ds2.FieldByName('Category').AsString); - Assert.areEqual(ds.FieldByName('Common_Name').AsString, ds2.FieldByName('Common_Name').AsString); - Assert.areEqual(ds.FieldByName('Species Name').AsString, ds2.FieldByName('Species Name').AsString); - Assert.areEqual(ds.FieldByName('Length (cm)').AsString, ds2.FieldByName('Length (cm)').AsString); - Assert.areEqual(ds.FieldByName('Length_In').AsInteger, ds2.FieldByName('Length_In').AsInteger); - Assert.areEqual(ds.FieldByName('Notes').AsString, ds2.FieldByName('Notes').AsString); - Assert.areEqual(ds.FieldByName('Graphic').AsString, ds2.FieldByName('Graphic').AsString); -end; - procedure TTestRouting.SetUp; begin FControllers := TObjectList.Create; diff --git a/unittests/general/TestServer/TestServerControllerU.pas b/unittests/general/TestServer/TestServerControllerU.pas index 8accc345..f4f88280 100644 --- a/unittests/general/TestServer/TestServerControllerU.pas +++ b/unittests/general/TestServer/TestServerControllerU.pas @@ -34,7 +34,8 @@ uses FireDAC.Comp.Client, System.Generics.Collections, Data.DB, - BusinessObjectsU; + BusinessObjectsU, MVCFramework.Serializer.Commons, System.Classes, + System.UITypes; type @@ -412,6 +413,60 @@ type procedure Action1or2; end; + +// action result types + [MVCNameCase(ncLowerCase)] + TSum = class + private + fValue: Integer; + public + property Value: Integer read fValue write fValue; + end; + + [MVCNameCase(ncLowerCase)] + TComplexObject = class + private + fValue: Integer; + FPeople: TPeople; + FPerson: TPerson; + procedure SetPeople(const Value: TPeople); + procedure SetPerson(const Value: TPerson); + public + destructor Destroy; override; + property Value: Integer read fValue write fValue; + property Person: TPerson read FPerson write SetPerson; + property People: TPeople read FPeople write SetPeople; + end; +// action result types - end + + [MVCPath('/api/v1/actionresult')] + TTestActionResultController = class(TMVCController) + public + [MVCPath('/sums/($a)/($b)')] + [MVCHTTPMethod([httpGET])] + function GetObject(a,b: Integer): TSum; + [MVCPath('/complex')] + [MVCHTTPMethod([httpGET])] + function GetComplexObject: TComplexObject; + [MVCPath('/people')] + [MVCHTTPMethod([httpGET])] + function GetPeople: TObjectList; + [MVCPath('/photo')] + [MVCHTTPMethod([httpGET])] + function GetPhoto: TStream; + [MVCPath('/string')] + [MVCHTTPMethod([httpGET])] + function GetString: String; + [MVCPath('/enum')] + [MVCHTTPMethod([httpGET])] + function GetEnum: TFontStyle; + [MVCPath('/bool')] + [MVCHTTPMethod([httpGET])] + function GetBool: Boolean; + end; + + + implementation uses @@ -419,11 +474,9 @@ uses System.JSON, Web.HTTPApp, Generics.Collections, - MVCFramework.Serializer.Commons, MVCFramework.Serializer.Defaults, MVCFramework.DuckTyping, - System.IOUtils, - System.Classes, MVCFramework.Tests.Serializer.Entities; + System.IOUtils, MVCFramework.Tests.Serializer.Entities; { TTestServerController } @@ -1226,4 +1279,67 @@ begin Render(HTTP_STATUS.OK); end; +{ TTestActionResultController } + +function TTestActionResultController.GetBool: Boolean; +begin + Result := True; +end; + +function TTestActionResultController.GetComplexObject: TComplexObject; +begin + Result := TComplexObject.Create; + Result.Value := 1234; + Result.Person := TPerson.GetNew('Danielem', 'Teti', EncodeDate(1920,12,23), True); + Result.People := TPerson.GetList(); +end; + +function TTestActionResultController.GetEnum: TFontStyle; +begin + Result := TFontStyle.fsBold; +end; + +function TTestActionResultController.GetPeople: TObjectList; +begin + Result := TPerson.GetList(); +end; + +function TTestActionResultController.GetPhoto: TStream; +begin + Context.Response.ContentType := TMVCMediaType.IMAGE_X_PNG; + Result := TFileStream.Create('sample.png', fmOpenRead or fmShareDenyNone); +end; + +function TTestActionResultController.GetString: String; +begin + Result := 'Hello World'; +end; + +function TTestActionResultController.GetObject(a, b: Integer): TSum; +begin + StatusCode := 201; + Context.Response.SetCustomHeader('X-PIPPO','PLUTO'); + Result := TSum.Create; + Result.Value := a+b; +end; + +{ TComplexObject } + +destructor TComplexObject.Destroy; +begin + FPerson.Free; + FPeople.Free; + inherited; +end; + +procedure TComplexObject.SetPeople(const Value: TPeople); +begin + FPeople := Value; +end; + +procedure TComplexObject.SetPerson(const Value: TPerson); +begin + FPerson := Value; +end; + end. diff --git a/unittests/general/TestServer/WebModuleUnit.pas b/unittests/general/TestServer/WebModuleUnit.pas index 0d98518e..86c9da51 100644 --- a/unittests/general/TestServer/WebModuleUnit.pas +++ b/unittests/general/TestServer/WebModuleUnit.pas @@ -90,6 +90,7 @@ begin .AddController(TTestServerControllerActionFilters) .AddController(TTestPrivateServerControllerCustomAuth) .AddController(TTestMultiPathController) + .AddController(TTestActionResultController) .AddController(TTestJSONRPCController, '/jsonrpc') .AddController(TTestJSONRPCControllerWithGet, '/jsonrpcwithget') .AddController(TMVCActiveRecordController, diff --git a/unittests/general/UnitTestReports/dmvcframework_nunit_win64.xml b/unittests/general/UnitTestReports/dmvcframework_nunit_win64.xml index c882bbe0..e2ec40f6 100644 --- a/unittests/general/UnitTestReports/dmvcframework_nunit_win64.xml +++ b/unittests/general/UnitTestReports/dmvcframework_nunit_win64.xml @@ -1,895 +1,218 @@  - + - + - + - + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + @@ -931,7 +254,7 @@ - + @@ -946,7 +269,7 @@ - + @@ -970,7 +293,631 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -978,22 +925,75 @@ - + - + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d8fa301a190ccb12af829584df2bf59874716b15 Mon Sep 17 00:00:00 2001 From: danieleteti Date: Mon, 13 Mar 2023 14:47:17 +0000 Subject: [PATCH 02/31] chore(docs): update TOC --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fa5c1f9f..8942c0d4 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ - [How to partecipate to DMVCFramework development and/or tests](#how-to-partecipate-to-dmvcframework-development-andor-tests) - [Sponsors](#sponsors) - [What users say about DMVCFramework](#what-users-say-about-dmvcframework) - - [What's New in 3.2.3-radium](#whats-new-in-323-radium) + - [What's New in dmvcframework-3.3.0-fluorine (currently in beta a.k.a. "repo version")](#whats-new-in-dmvcframework-330-fluorine-currently-in-beta-aka-repo-version) + - [What's New in dmvcframework-3.2.3-radium](#whats-new-in-dmvcframework-323-radium) - [Bug Fix in 3.2.3-radium](#bug-fix-in-323-radium) - [What's new in DelphiMVCFramework-3.2.2-nitrogen](#whats-new-in-delphimvcframework-322-nitrogen) - [Bug Fixes in 3.2.2-nitrogen](#bug-fixes-in-322-nitrogen) From 357837a380e133a715658b785a561ce0ed5903b9 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Mon, 13 Mar 2023 18:01:04 +0100 Subject: [PATCH 03/31] Supports Record and Array of Record (WIP) --- .../TestServer/TestServerControllerU.pas | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/unittests/general/TestServer/TestServerControllerU.pas b/unittests/general/TestServer/TestServerControllerU.pas index f4f88280..0cd115f5 100644 --- a/unittests/general/TestServer/TestServerControllerU.pas +++ b/unittests/general/TestServer/TestServerControllerU.pas @@ -463,6 +463,21 @@ type [MVCPath('/bool')] [MVCHTTPMethod([httpGET])] function GetBool: Boolean; + [MVCPath('/strdict')] + [MVCHTTPMethod([httpGET])] + function GetStrDict: TMVCStringDictionary; + [MVCPath('/TSimpleRecord')] + [MVCHTTPMethod([httpGET])] + function GetTSimpleRecord: TSimpleRecord; + [MVCPath('/ArrayOf/TSimpleRecord')] + [MVCHTTPMethod([httpGET])] + function GetArrayOfTSimpleRecord: TArray; + [MVCPath('/TComplexRecord')] + [MVCHTTPMethod([httpGET])] + function GetTComplexRecord: TComplexRecord; + [MVCPath('/ArrayOf/TComplexRecord')] + [MVCHTTPMethod([httpGET])] + function GetArrayOfTComplexRecord: TComplexRecordArray; end; @@ -1281,6 +1296,26 @@ end; { TTestActionResultController } +function TTestActionResultController.GetArrayOfTComplexRecord: TComplexRecordArray; +begin + SetLength(Result,3); + Result[0] := TComplexRecord.Create; + Result[1] := TComplexRecord.Create; + Result[2] := TComplexRecord.Create; + + Result[0].StringProperty := 'item 0'; + Result[1].StringProperty := 'item 1'; + Result[2].StringProperty := 'item 2'; +end; + +function TTestActionResultController.GetArrayOfTSimpleRecord: TArray; +begin + SetLength(Result, 3); + Result[0] := TSimpleRecord.Create; + Result[1] := TSimpleRecord.Create; + Result[2] := TSimpleRecord.Create; +end; + function TTestActionResultController.GetBool: Boolean; begin Result := True; @@ -1310,11 +1345,26 @@ begin Result := TFileStream.Create('sample.png', fmOpenRead or fmShareDenyNone); end; +function TTestActionResultController.GetStrDict: TMVCStringDictionary; +begin + Result := StrDict.Add('first_name','Daniele').Add('last_name','Teti'); +end; + function TTestActionResultController.GetString: String; begin Result := 'Hello World'; end; +function TTestActionResultController.GetTComplexRecord: TComplexRecord; +begin + Result := TComplexRecord.Create; +end; + +function TTestActionResultController.GetTSimpleRecord: TSimpleRecord; +begin + Result := TSimpleRecord.Create; +end; + function TTestActionResultController.GetObject(a, b: Integer): TSum; begin StatusCode := 201; From 19c9cd3df4f6f82aa1ce09c6cf92606c0dd15468 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Tue, 14 Mar 2023 08:56:00 +0100 Subject: [PATCH 04/31] Added support for records and array of record in function/action return --- README.md | 6 ++- sources/MVCFramework.Serializer.HTML.pas | 15 +++++- sources/MVCFramework.Serializer.Intf.pas | 7 +++ ...VCFramework.Serializer.JsonDataObjects.pas | 49 +++++++++++++++++++ sources/MVCFramework.pas | 15 ++++++ unittests/general/TestServer/TestServer.dpr | 4 +- unittests/general/TestServer/TestServer.dproj | 2 + 7 files changed, 94 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8942c0d4..f867d018 100644 --- a/README.md +++ b/README.md @@ -214,9 +214,11 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma > "Our wishes are coming true" -- one Delphi programmer after a small dmvcframework demo for an IT department of a very important national research institute -## What's New in dmvcframework-3.3.0-fluorine (currently in beta a.k.a. "repo version") +## What's New in dmvcframework-3.3.0-fluorine-beta (currently in beta a.k.a. "repo version") + +- ⚡ Add the ability to use records in swagger param and response attributes. [PR 649](https://github.com/danieleteti/delphimvcframework/pull/649). Thanks to [orionlaw](https://github.com/orionlaw) +- 🐞 FIX [Issue 648](https://github.com/danieleteti/delphimvcframework/issues/648). Thanks to [sf-spb](https://github.com/sf-spb) -- 🐞 FIX [Issue 648](https://github.com/danieleteti/delphimvcframework/issues/648) Thanks to [sf-spb](https://github.com/sf-spb) ## What's New in dmvcframework-3.2.3-radium diff --git a/sources/MVCFramework.Serializer.HTML.pas b/sources/MVCFramework.Serializer.HTML.pas index 4b8eb36e..3492bba5 100644 --- a/sources/MVCFramework.Serializer.HTML.pas +++ b/sources/MVCFramework.Serializer.HTML.pas @@ -77,7 +77,6 @@ type const ASerializationAction: TMVCSerializationAction = nil ): string; overload; - function SerializeCollection( const AList: TObject; const AType: TMVCSerializationType = stDefault; @@ -151,6 +150,12 @@ type const AIgnoredFields: TMVCIgnoredList = []; const ANameCase: TMVCNameCase = ncAsIs ); + + function SerializeArrayOfRecord( + var ATValueContainingAnArray: TValue; + const AType: TMVCSerializationType = stDefault; + const AIgnoredAttributes: TMVCIgnoredList = nil; + const ASerializationAction: TMVCSerializationAction = nil): string; end; implementation @@ -274,6 +279,14 @@ begin RaiseNotImplemented; end; +function TMVCHTMLSerializer.SerializeArrayOfRecord( + var ATValueContainingAnArray: TValue; const AType: TMVCSerializationType; + const AIgnoredAttributes: TMVCIgnoredList; + const ASerializationAction: TMVCSerializationAction): string; +begin + RaiseNotImplemented; +end; + function TMVCHTMLSerializer.SerializeCollection(const AList: IInterface; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): string; diff --git a/sources/MVCFramework.Serializer.Intf.pas b/sources/MVCFramework.Serializer.Intf.pas index 0a07a79f..b4bd50d5 100644 --- a/sources/MVCFramework.Serializer.Intf.pas +++ b/sources/MVCFramework.Serializer.Intf.pas @@ -94,6 +94,13 @@ type const ASerializationAction: TMVCSerializationAction = nil ): string; overload; + function SerializeArrayOfRecord( + var ATValueContainingAnArray: TValue; + const AType: TMVCSerializationType = stDefault; + const AIgnoredAttributes: TMVCIgnoredList = nil; + const ASerializationAction: TMVCSerializationAction = nil + ): string; overload; + function SerializeCollection( const AList: TObject; const AType: TMVCSerializationType = stDefault; diff --git a/sources/MVCFramework.Serializer.JsonDataObjects.pas b/sources/MVCFramework.Serializer.JsonDataObjects.pas index b82b0e11..76fb5bdf 100644 --- a/sources/MVCFramework.Serializer.JsonDataObjects.pas +++ b/sources/MVCFramework.Serializer.JsonDataObjects.pas @@ -174,6 +174,13 @@ type const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = nil; const ASerializationAction: TMVCSerializationAction = nil): string; overload; + function SerializeArrayOfRecord( + var ATValueContainingAnArray: TValue; + const AType: TMVCSerializationType = stDefault; + const AIgnoredAttributes: TMVCIgnoredList = nil; + const ASerializationAction: TMVCSerializationAction = nil + ): string; overload; + procedure RecordToJsonObject(const ARecord: Pointer; const ARecordTypeInfo: PTypeInfo; const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList); @@ -3042,6 +3049,48 @@ begin end; end; +function TMVCJsonDataObjectsSerializer.SerializeArrayOfRecord( + var ATValueContainingAnArray: TValue; const AType: TMVCSerializationType; + const AIgnoredAttributes: TMVCIgnoredList; + const ASerializationAction: TMVCSerializationAction): string; +var + I: Integer; + lCurrentArrayItem: TValue; + lJSONArr: TJsonArray; + lJObj: TJsonObject; +begin + if not ATValueContainingAnArray.IsArray then + begin + raise EMVCSerializationException.Create(String(ATValueContainingAnArray.TypeInfo^.Name) + ' is not an array'); + end; + if ATValueContainingAnArray.GetArrayLength = 0 then + begin + Result := '[]'; + end; + + lJSONArr := TJsonArray.Create; + try + for I := 0 to ATValueContainingAnArray.GetArrayLength - 1 do + begin + lJObj := lJSONArr.AddObject; + lCurrentArrayItem := ATValueContainingAnArray.GetArrayElement(I); + InternalRecordToJsonObject( + lCurrentArrayItem.GetReferenceToRawData, + lCurrentArrayItem.TypeInfo, + lJObj, + TMVCSerializationType.stFields, + nil, + nil, + nil, + nil + ); + end; + Result := lJSONArr.ToJSON(); + finally + lJSONArr.free; + end; +end; + function TMVCJsonDataObjectsSerializer.SerializeCollection(const AList: IInterface; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): string; begin diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index 8ab51afa..d0644443 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -2532,6 +2532,21 @@ begin lResponseObject.Free; end end; + tkRecord: + begin + lSelectedController.Render( + lSelectedController.Serializer(lSelectedController.GetContentType) + .SerializeRecord(lInvokeResult.GetReferenceToRawData, + lInvokeResult.TypeInfo, + TMVCSerializationType.stFields,nil,nil)); + end; + tkArray, tkDynArray: + begin + lSelectedController.Render( + lSelectedController.Serializer(lSelectedController.GetContentType) + .SerializeArrayOfRecord(lInvokeResult, + TMVCSerializationType.stFields,nil,nil)); + end; tkUString, tkString: begin lSelectedController.Render(lInvokeResult.AsString); diff --git a/unittests/general/TestServer/TestServer.dpr b/unittests/general/TestServer/TestServer.dpr index c7ea998c..f9a79833 100644 --- a/unittests/general/TestServer/TestServer.dpr +++ b/unittests/general/TestServer/TestServer.dpr @@ -24,7 +24,9 @@ uses MVCFramework.Tests.Serializer.Entities in '..\..\common\MVCFramework.Tests.Serializer.Entities.pas', FDConnectionConfigU in '..\..\common\FDConnectionConfigU.pas', Entities in '..\Several\Entities.pas', - EntitiesProcessors in '..\Several\EntitiesProcessors.pas'; + EntitiesProcessors in '..\Several\EntitiesProcessors.pas', + MVCFramework.JSONRPC.Client in '..\..\..\sources\MVCFramework.JSONRPC.Client.pas', + MVCFramework.JSONRPC in '..\..\..\sources\MVCFramework.JSONRPC.pas'; {$R *.res} diff --git a/unittests/general/TestServer/TestServer.dproj b/unittests/general/TestServer/TestServer.dproj index a2e223bf..0f8809cd 100644 --- a/unittests/general/TestServer/TestServer.dproj +++ b/unittests/general/TestServer/TestServer.dproj @@ -140,6 +140,8 @@ + + Base From 2f69a1adffd51d7c5bd8ec161b4968f86325e9b4 Mon Sep 17 00:00:00 2001 From: danieleteti Date: Tue, 14 Mar 2023 07:56:36 +0000 Subject: [PATCH 05/31] chore(docs): update TOC --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f867d018..adfea0cb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ - [How to partecipate to DMVCFramework development and/or tests](#how-to-partecipate-to-dmvcframework-development-andor-tests) - [Sponsors](#sponsors) - [What users say about DMVCFramework](#what-users-say-about-dmvcframework) - - [What's New in dmvcframework-3.3.0-fluorine (currently in beta a.k.a. "repo version")](#whats-new-in-dmvcframework-330-fluorine-currently-in-beta-aka-repo-version) + - [What's New in dmvcframework-3.3.0-fluorine-beta (currently in beta a.k.a. "repo version")](#whats-new-in-dmvcframework-330-fluorine-beta-currently-in-beta-aka-repo-version) - [What's New in dmvcframework-3.2.3-radium](#whats-new-in-dmvcframework-323-radium) - [Bug Fix in 3.2.3-radium](#bug-fix-in-323-radium) - [What's new in DelphiMVCFramework-3.2.2-nitrogen](#whats-new-in-delphimvcframework-322-nitrogen) From 5d7711c65efb96d6344f30cd32c6fa626911b7f2 Mon Sep 17 00:00:00 2001 From: danieleteti Date: Fri, 21 Apr 2023 14:41:50 +0000 Subject: [PATCH 06/31] chore(docs): update TOC --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08056dca..2a166752 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ - [How to partecipate to DMVCFramework development and/or tests](#how-to-partecipate-to-dmvcframework-development-andor-tests) - [Sponsors](#sponsors) - [What users say about DMVCFramework](#what-users-say-about-dmvcframework) - - [What's New in dmvcframework-3.3.0-fluorine (currently in beta a.k.a. "repo version")](#whats-new-in-dmvcframework-330-fluorine-currently-in-beta-aka-repo-version) + - [What's New in dmvcframework-3.3.0-fluorine](#whats-new-in-dmvcframework-330-fluorine) - [What's New in dmvcframework-3.2.3-radium](#whats-new-in-dmvcframework-323-radium) - [Bug Fix in 3.2.3-radium](#bug-fix-in-323-radium) - [What's new in DelphiMVCFramework-3.2.2-nitrogen](#whats-new-in-delphimvcframework-322-nitrogen) From d122bf300d136d51aed635a64bb785eaa4ed4531 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Thu, 18 May 2023 09:09:05 +0200 Subject: [PATCH 07/31] (WIP) --- lib/loggerpro/LoggerPro.pas | 1 + lib/swagdoc/Source/SwagDoc.dpk | 1 + lib/swagdoc/Source/SwagDoc.dproj | 1 + packages/d113/dmvcframework_group.groupproj | 8 +- .../data/activerecorddb_firebird_script.sql | 2 +- samples/renders/RenderSampleControllerU.pas | 41 ++- samples/renders/renders.dproj | 244 +++++++++--------- sources/MVCFramework.pas | 5 +- .../TestServer/TestServerControllerU.pas | 34 ++- 9 files changed, 204 insertions(+), 133 deletions(-) diff --git a/lib/loggerpro/LoggerPro.pas b/lib/loggerpro/LoggerPro.pas index a03201f1..57ecf29c 100644 --- a/lib/loggerpro/LoggerPro.pas +++ b/lib/loggerpro/LoggerPro.pas @@ -358,6 +358,7 @@ function GetDefaultFormatSettings: TFormatSettings; begin Result.DateSeparator := '-'; Result.TimeSeparator := ':'; + Result.DecimalSeparator := '.'; Result.ShortDateFormat := 'YYYY-MM-DD HH:NN:SS:ZZZ'; Result.ShortTimeFormat := 'HH:NN:SS'; end; diff --git a/lib/swagdoc/Source/SwagDoc.dpk b/lib/swagdoc/Source/SwagDoc.dpk index cac34e20..a7aa761a 100644 --- a/lib/swagdoc/Source/SwagDoc.dpk +++ b/lib/swagdoc/Source/SwagDoc.dpk @@ -26,6 +26,7 @@ package SwagDoc; {$DEFINE DEBUG} {$ENDIF IMPLICITBUILDING} {$DESCRIPTION 'SwagDoc Library'} +{$LIBSUFFIX '113'} {$RUNONLY} {$IMPLICITBUILD ON} diff --git a/lib/swagdoc/Source/SwagDoc.dproj b/lib/swagdoc/Source/SwagDoc.dproj index c82c5463..a69151d4 100644 --- a/lib/swagdoc/Source/SwagDoc.dproj +++ b/lib/swagdoc/Source/SwagDoc.dproj @@ -96,6 +96,7 @@ 0 1033 CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 113 false diff --git a/packages/d113/dmvcframework_group.groupproj b/packages/d113/dmvcframework_group.groupproj index 54349cfd..17da6422 100644 --- a/packages/d113/dmvcframework_group.groupproj +++ b/packages/d113/dmvcframework_group.groupproj @@ -10,7 +10,7 @@ - ..\..\lib\swagdoc\Source\SwagDoc.dproj;..\..\lib\loggerpro\packages\d113\loggerproRT.dproj + ..\..\lib\loggerpro\packages\d113\loggerproRT.dproj;..\..\lib\swagdoc\Source\SwagDoc.dproj dmvcframeworkRT.dproj @@ -41,13 +41,13 @@ - + - + - + diff --git a/samples/data/activerecorddb_firebird_script.sql b/samples/data/activerecorddb_firebird_script.sql index c9daae32..1640d1b2 100644 --- a/samples/data/activerecorddb_firebird_script.sql +++ b/samples/data/activerecorddb_firebird_script.sql @@ -7,7 +7,7 @@ CREATE TABLE articles ( CREATE TABLE customers ( id integer GENERATED BY DEFAULT AS IDENTITY, - code varchar(20) NOT NULL, + code varchar(20), description varchar(200), city varchar(200), rating INTEGER, diff --git a/samples/renders/RenderSampleControllerU.pas b/samples/renders/RenderSampleControllerU.pas index d87058fa..ac6f644d 100644 --- a/samples/renders/RenderSampleControllerU.pas +++ b/samples/renders/RenderSampleControllerU.pas @@ -32,7 +32,9 @@ uses MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Intf, - System.Rtti, BusinessObjectsU; + System.Rtti, + System.Generics.Collections, + BusinessObjectsU, Data.DB; type @@ -42,6 +44,18 @@ type procedure OnBeforeAction(AContext: TWebContext; const AActionName: string; var AHandled: Boolean); override; public + // Result BASED + [MVCHTTPMethod([httpGET])] + [MVCPath('/func/people')] + [MVCProduces('application/json')] + function GetPeople_AsObjectList_AsFunction: TEnumerable; + + [MVCHTTPMethod([httpGET])] + [MVCPath('/func/customers/simple')] + function GetCustomers_AsDataSet_AsFunction: TDataSet; + + + // Render BASED [MVCHTTPMethod([httpGET])] [MVCPath('/customers/simple')] procedure GetCustomers_AsDataSet; @@ -266,10 +280,9 @@ uses InMemoryDataU, JsonDataObjects, MVCFramework.Serializer.JsonDataObjects, - Data.DB, Web.HTTPApp, Graphics, - System.Types; + System.Types, FireDAC.Comp.Client; procedure DrawLogo(const Logo: TBitmap); var @@ -515,6 +528,20 @@ begin end; end; +function TRenderSampleController.GetCustomers_AsDataSet_AsFunction: TDataSet; +var + lDM: TMyDataModule; +begin + lDM := TMyDataModule.Create(nil); + try + lDM.qryCustomers.Open; + Result := TFDMemTable.Create(nil); + TFDMemTable(Result).CloneCursor(lDM.qryCustomers, True); + finally + lDM.Free; + end; +end; + procedure TRenderSampleController.GetCustomersAsDataSetWithRefLinks; var lDM: TMyDataModule; @@ -909,6 +936,14 @@ begin Render(HTTP_STATUS.OK, ObjectDict().Add('data', People)); end; +function TRenderSampleController.GetPeople_AsObjectList_AsFunction: TEnumerable; +begin + Result := TObjectList.Create(True); + TObjectList(Result).Add(TPerson.GetNew('Daniele','Teti', EncodeDate(1979, 11, 4), True)); + TObjectList(Result).Add(TPerson.GetNew('John','Doe', EncodeDate(1879, 10, 2), False)); + TObjectList(Result).Add(TPerson.GetNew('Jane','Doe', EncodeDate(1883, 1, 5), True)); +end; + procedure TRenderSampleController.GetPeople_AsObjectList_HATEOAS; var p: TPerson; diff --git a/samples/renders/renders.dproj b/samples/renders/renders.dproj index a8839b78..1ddbd51b 100644 --- a/samples/renders/renders.dproj +++ b/samples/renders/renders.dproj @@ -215,12 +215,12 @@ + true - true @@ -627,6 +627,127 @@ 0 + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset @@ -827,127 +948,6 @@ 1 - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index b609823d..b3fdd5c6 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -2315,7 +2315,6 @@ begin FControllers := TObjectList.Create(True); FApplicationSession := nil; FSavedOnBeforeDispatch := nil; - WebRequestHandler.CacheConnections := True; WebRequestHandler.MaxConnections := 4096; @@ -2554,6 +2553,10 @@ begin tkEnumeration: begin lSelectedController.Render(GetEnumName(lInvokeResult.TypeInfo, lInvokeResult.AsOrdinal)); + end; + tkFloat: + begin + lSelectedController.Render(FloatToStr(lInvokeResult.AsExtended, GetDefaultFormatSettings)); end else begin diff --git a/unittests/general/TestServer/TestServerControllerU.pas b/unittests/general/TestServer/TestServerControllerU.pas index 0cd115f5..471fd270 100644 --- a/unittests/general/TestServer/TestServerControllerU.pas +++ b/unittests/general/TestServer/TestServerControllerU.pas @@ -47,9 +47,10 @@ type fDataSet: TFDMemTable; protected procedure MVCControllerAfterCreate; override; - function GetDataSet: TDataSet; procedure MVCControllerBeforeDestroy; override; public + class function GetDataSet: TDataSet; + [MVCPath('/req/with/params/($par1)/($par2)/($par3)')] [MVCHTTPMethod([httpGET, httpDELETE])] procedure ReqWithParams; @@ -445,39 +446,58 @@ type [MVCPath('/sums/($a)/($b)')] [MVCHTTPMethod([httpGET])] function GetObject(a,b: Integer): TSum; + [MVCPath('/complex')] [MVCHTTPMethod([httpGET])] function GetComplexObject: TComplexObject; + [MVCPath('/people')] [MVCHTTPMethod([httpGET])] function GetPeople: TObjectList; + [MVCPath('/photo')] [MVCHTTPMethod([httpGET])] function GetPhoto: TStream; + [MVCPath('/string')] [MVCHTTPMethod([httpGET])] function GetString: String; + [MVCPath('/enum')] [MVCHTTPMethod([httpGET])] function GetEnum: TFontStyle; + [MVCPath('/bool')] [MVCHTTPMethod([httpGET])] function GetBool: Boolean; + + [MVCPath('/float')] + [MVCHTTPMethod([httpGET])] + function GetFloat: Double; + [MVCPath('/strdict')] [MVCHTTPMethod([httpGET])] function GetStrDict: TMVCStringDictionary; + [MVCPath('/TSimpleRecord')] [MVCHTTPMethod([httpGET])] function GetTSimpleRecord: TSimpleRecord; + [MVCPath('/ArrayOf/TSimpleRecord')] [MVCHTTPMethod([httpGET])] function GetArrayOfTSimpleRecord: TArray; + [MVCPath('/TComplexRecord')] [MVCHTTPMethod([httpGET])] function GetTComplexRecord: TComplexRecord; + [MVCPath('/ArrayOf/TComplexRecord')] [MVCHTTPMethod([httpGET])] function GetArrayOfTComplexRecord: TComplexRecordArray; + + [MVCPath('/dataset/list')] + [MVCHTTPMethod([httpGET])] + function GetDataSetRecords: TDataSet; end; @@ -580,7 +600,7 @@ begin end; -function TTestServerController.GetDataSet: TDataSet; +class function TTestServerController.GetDataSet: TDataSet; begin Result := TFDMemTable.Create(nil); TFDMemTable(Result).LoadFromFile(TPath.Combine(AppPath, 'customers.json')); @@ -1329,11 +1349,21 @@ begin Result.People := TPerson.GetList(); end; +function TTestActionResultController.GetDataSetRecords: TDataSet; +begin + Result := TTestServerController.GetDataSet; +end; + function TTestActionResultController.GetEnum: TFontStyle; begin Result := TFontStyle.fsBold; end; +function TTestActionResultController.GetFloat: Double; +begin + Result := 3.1415; +end; + function TTestActionResultController.GetPeople: TObjectList; begin Result := TPerson.GetList(); From 61d021b92ab7d8c90ac87c233c72470a14301c8b Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Wed, 19 Jul 2023 11:10:21 +0200 Subject: [PATCH 08/31] Improved dataset handling for functional actions. --- README.md | 83 +++++++++++++- samples/data/people_dataset.json | 1 + .../funcion_actions_showcase/ControllerU.pas | 51 ++++++++- samples/funcion_actions_showcase/MainDMU.dfm | 101 ++++++++++++++++++ samples/funcion_actions_showcase/MainDMU.pas | 26 +++++ .../function_actions_showcase.dpr | 3 +- .../function_actions_showcase.dproj | 5 + sources/MVCFramework.FireDAC.Utils.pas | 11 +- ...VCFramework.Serializer.JsonDataObjects.pas | 36 +++++-- sources/MVCFramework.pas | 19 ++-- 10 files changed, 308 insertions(+), 28 deletions(-) create mode 100644 samples/data/people_dataset.json create mode 100644 samples/funcion_actions_showcase/MainDMU.dfm create mode 100644 samples/funcion_actions_showcase/MainDMU.pas diff --git a/README.md b/README.md index 2ed7927d..127e4a18 100644 --- a/README.md +++ b/README.md @@ -231,12 +231,89 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma ## What's New in the next "repo version" a.k.a. 3.4.0-neon -- Added support for dotEnv multiline keys - added dotEnv show case -- Added MSHeap memory manager for Win32 and Win64 (https://github.com/RDP1974/DelphiMSHeap) +- ⚡ Added support for dotEnv multiline keys - added dotEnv show case + +- ⚡ Added MSHeap memory manager for Win32 and Win64 (https://github.com/RDP1974/DelphiMSHeap) + - 🐞 FIX [Issue 664](https://github.com/danieleteti/delphimvcframework/issues/664) Thanks to [MPannier](https://github.com/MPannier) + - 🐞 FIX [Issue 667](https://github.com/danieleteti/delphimvcframework/issues/667) + - 🐞 FIX Wrong comparison in checks for ro/RW/PK fields in `TMVCActiveRecord` -- Wizard updated to be dotEnv aware + +- ⚡ Wizard updated to be dotEnv aware + +- ⚡ Better error message in case of serialization of `TArray` + +- ⚡ Improved serialization of `TObjectList` (however `ObjectDict` is still the preferred way to serialize multiple datasets). + +- ⚡ Added static method for easier cloning of FireDAC dataset into `TFDMemTable`. + + - `class function CloneFrom(const FDDataSet: TFDDataSet): TFDMemTable` + + - Check sample "function_actions_showcase.dproj" for more info. + +- ⚡ Functional Actions + + - In addition to the classic `procedure` based actions, now it's possibile to use functions as actions. The `Result` variable is automatically rendered and, if it is an object, its memory is freed. + + ```pascal + type + [MVCNameCase(ncCamelCase)] + TPersonRec = record + FirstName, LastName: String; + Age: Integer; + class function Create: TPersonRec; static; + end; + + [MVCNameCase(ncCamelCase)] + TPerson = class + private + fAge: Integer; + fFirstName, fLastName: String; + public + property FirstName: String read fFirstName write fFirstName; + property LastName: String read fLastName write fLastName; + property Age: Integer read fAge write fAge; + end; + + [MVCPath('/api')] + TMyController = class(TMVCController) + public + { actions returning a simple type } + [MVCPath('/sumsasinteger/($A)/($B)')] + function GetSum(const A, B: Integer): Integer; + [MVCPath('/sumsasfloat/($A)/($B)')] + function GetSumAsFloat(const A, B: Extended): Extended; + + { actions returning records } + [MVCPath('/records/single')] + function GetSingleRecord: TPersonRec; + [MVCPath('/records/multiple')] + function GetMultipleRecords: TArray; + + { actions returning objects } + [MVCPath('/objects/single')] + function GetSingleObject: TPerson; + [MVCPath('/objects/multiple')] + function GetMultipleObjects: TObjectList; + + { actions returning datasets } + [MVCPath('/datasets/single')] + function GetSingleDataSet: TDataSet; + [MVCPath('/datasets/multiple')] + function GetMultipleDataSet: TEnumerable; + [MVCPath('/datasets/multiple2')] + function GetMultipleDataSet2: IMVCObjectDictionary; + + { customize response headers } + [MVCPath('/headers')] + function GetWithCustomHeaders: TObjectList; + end; + ``` + + Check sample "function_actions_showcase.dproj" for more info. + diff --git a/samples/data/people_dataset.json b/samples/data/people_dataset.json new file mode 100644 index 00000000..5b7bd3ea --- /dev/null +++ b/samples/data/people_dataset.json @@ -0,0 +1 @@ +{"FDBS":{"Version":16,"Manager":{"UpdatesRegistry":true,"TableList":[{"class":"Table","Name":"FDMemTable1","SourceName":"FDMemTable1","TabID":0,"EnforceConstraints":false,"MinimumCapacity":50,"CheckNotNull":false,"ColumnList":[{"class":"Column","Name":"id","SourceName":"id","SourceID":1,"DataType":"Int64","Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OInKey":true,"OriginColName":"id"},{"class":"Column","Name":"last_name","SourceName":"last_name","SourceID":2,"DataType":"WideString","Size":100,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"last_name","SourceSize":100},{"class":"Column","Name":"first_name","SourceName":"first_name","SourceID":3,"DataType":"WideString","Size":100,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"first_name","SourceSize":100},{"class":"Column","Name":"dob","SourceName":"dob","SourceID":4,"DataType":"Date","Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"dob"},{"class":"Column","Name":"full_name","SourceName":"full_name","SourceID":5,"DataType":"WideString","Size":80,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"full_name","SourceSize":80},{"class":"Column","Name":"is_male","SourceName":"is_male","SourceID":6,"DataType":"Boolean","Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"is_male"},{"class":"Column","Name":"note","SourceName":"note","SourceID":7,"DataType":"WideMemo","Searchable":true,"AllowNull":true,"BlobData":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"note"},{"class":"Column","Name":"photo","SourceName":"photo","SourceID":8,"DataType":"Blob","Searchable":true,"AllowNull":true,"BlobData":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"photo"},{"class":"Column","Name":"person_type","SourceName":"person_type","SourceID":9,"DataType":"WideString","Size":8190,"Searchable":true,"AllowNull":true,"BlobData":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"person_type","SourceSize":8190},{"class":"Column","Name":"salary","SourceName":"salary","SourceID":10,"DataType":"Currency","Precision":19,"Scale":4,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"salary","SourcePrecision":19,"SourceScale":4},{"class":"Column","Name":"annual_bonus","SourceName":"annual_bonus","SourceID":11,"DataType":"Currency","Precision":19,"Scale":4,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginColName":"annual_bonus","SourcePrecision":19,"SourceScale":4}],"ConstraintList":[],"ViewList":[],"RowList":[{"RowID":0,"Original":{"id":235,"last_name":"Richards","first_name":"Reed","dob":"19851104","full_name":"Reed Richards","is_male":true,"person_type":"person","photo":""}},{"RowID":1,"Original":{"id":236,"last_name":"Parker","first_name":"Peter","dob":"19851104","full_name":"Peter Parker","is_male":true,"person_type":"employee","salary":2100,"photo":""}},{"RowID":2,"Original":{"id":237,"last_name":"Storm","first_name":"Sue","dob":"19751014","full_name":"Sue Storm","is_male":false,"person_type":"employee","salary":2200,"photo":""}},{"RowID":3,"Original":{"id":238,"last_name":"Banner","first_name":"Bruce","dob":"19751104","full_name":"Bruce Banner","is_male":true,"person_type":"manager","salary":2800,"annual_bonus":5000,"photo":""}}]}],"RelationList":[],"UpdatesJournal":{"SavePoint":4,"Changes":[]}}}} \ No newline at end of file diff --git a/samples/funcion_actions_showcase/ControllerU.pas b/samples/funcion_actions_showcase/ControllerU.pas index 34d90546..b92051dd 100644 --- a/samples/funcion_actions_showcase/ControllerU.pas +++ b/samples/funcion_actions_showcase/ControllerU.pas @@ -4,7 +4,7 @@ interface uses MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons, - System.Generics.Collections; + System.Generics.Collections, Data.DB; type [MVCNameCase(ncCamelCase)] @@ -46,6 +46,14 @@ type [MVCPath('/objects/multiple')] function GetMultipleObjects: TObjectList; + { actions returning datasets } + [MVCPath('/datasets/single')] + function GetSingleDataSet: TDataSet; + [MVCPath('/datasets/multiple')] + function GetMultipleDataSet: TEnumerable; + [MVCPath('/datasets/multiple2')] + function GetMultipleDataSet2: IMVCObjectDictionary; + { customize response headers } [MVCPath('/headers')] function GetWithCustomHeaders: TObjectList; @@ -54,10 +62,38 @@ type implementation uses - System.SysUtils, MVCFramework.Logger, System.StrUtils, System.DateUtils; + System.SysUtils, MVCFramework.Logger, System.StrUtils, System.DateUtils, + MainDMU, FireDAC.Comp.Client, MVCFramework.FireDAC.Utils; { TMyController } +function TMyController.GetMultipleDataSet: TEnumerable; +begin + var lDM := TdmMain.Create(nil); + try + lDM.dsPeople.Open; + var lList := TObjectList.Create; + lList.Add(TFDMemTable.CloneFrom(lDM.dsPeople)); + lList.Add(TFDMemTable.CloneFrom(lDM.dsPeople)); + Result := lList; + finally + lDM.Free; + end; +end; + +function TMyController.GetMultipleDataSet2: IMVCObjectDictionary; +begin + var lDM := TdmMain.Create(nil); + try + lDM.dsPeople.Open; + Result := ObjectDict() + .Add('people1', TFDMemTable.CloneFrom(lDM.dsPeople)) + .Add('people2', TFDMemTable.CloneFrom(lDM.dsPeople)); + finally + lDM.Free; + end; +end; + function TMyController.GetMultipleObjects: TObjectList; begin Result := TObjectList.Create; @@ -90,6 +126,17 @@ begin Inc(Result[2].Age, 20); end; +function TMyController.GetSingleDataSet: TDataSet; +begin + var lDM := TdmMain.Create(nil); + try + lDM.dsPeople.Open; + Result := TFDMemTable.CloneFrom(lDM.dsPeople); + finally + lDM.Free; + end; +end; + function TMyController.GetSingleObject: TPerson; begin Result := TPerson.Create; diff --git a/samples/funcion_actions_showcase/MainDMU.dfm b/samples/funcion_actions_showcase/MainDMU.dfm new file mode 100644 index 00000000..6a3e36e8 --- /dev/null +++ b/samples/funcion_actions_showcase/MainDMU.dfm @@ -0,0 +1,101 @@ +object dmMain: TdmMain + Height = 162 + Width = 312 + object dsPeople: TFDMemTable + Active = True + FetchOptions.AssignedValues = [evMode] + FetchOptions.Mode = fmAll + ResourceOptions.AssignedValues = [rvPersistent, rvSilentMode] + ResourceOptions.Persistent = True + ResourceOptions.SilentMode = True + UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates] + UpdateOptions.CheckRequired = False + UpdateOptions.AutoCommitUpdates = True + Left = 176 + Top = 88 + Content = { + 4144425310000000CA060000FF00010001FF02FF03040016000000460044004D + 0065006D005400610062006C0065003100050016000000460044004D0065006D + 005400610062006C0065003100060000000000070000080032000000090000FF + 0AFF0B04000400000069006400050004000000690064000C00010000000E000D + 000F000110000111000112000113000114000115000116000400000069006400 + FEFF0B0400120000006C006100730074005F006E0061006D0065000500120000 + 006C006100730074005F006E0061006D0065000C00020000000E001700180064 + 0000000F00011000011100011200011300011400011600120000006C00610073 + 0074005F006E0061006D006500190064000000FEFF0B04001400000066006900 + 7200730074005F006E0061006D00650005001400000066006900720073007400 + 5F006E0061006D0065000C00030000000E0017001800640000000F0001100001 + 110001120001130001140001160014000000660069007200730074005F006E00 + 61006D006500190064000000FEFF0B04000600000064006F0062000500060000 + 0064006F0062000C00040000000E001A000F0001100001110001120001130001 + 14000116000600000064006F006200FEFF0B040012000000660075006C006C00 + 5F006E0061006D006500050012000000660075006C006C005F006E0061006D00 + 65000C00050000000E0017001800500000000F00011000011100011200011300 + 01140001160012000000660075006C006C005F006E0061006D00650019005000 + 0000FEFF0B04000E000000690073005F006D0061006C00650005000E00000069 + 0073005F006D0061006C0065000C00060000000E001B000F0001100001110001 + 12000113000114000116000E000000690073005F006D0061006C006500FEFF0B + 0400080000006E006F00740065000500080000006E006F00740065000C000700 + 00000E001C000F00011000011D00011100011200011300011400011600080000 + 006E006F0074006500FEFF0B04000A000000700068006F0074006F0005000A00 + 0000700068006F0074006F000C00080000000E001E000F00011000011D000111 + 000112000113000114000116000A000000700068006F0074006F00FEFF0B0400 + 1600000070006500720073006F006E005F007400790070006500050016000000 + 70006500720073006F006E005F0074007900700065000C00090000000E001700 + 1800FE1F00000F00011000011D00011100011200011300011400011600160000 + 0070006500720073006F006E005F0074007900700065001900FE1F0000FEFF0B + 04000C000000730061006C0061007200790005000C000000730061006C006100 + 720079000C000A0000000E001F002000130000002100040000000F0001100001 + 11000112000113000114000116000C000000730061006C006100720079002200 + 13000000230004000000FEFF0B04001800000061006E006E00750061006C005F + 0062006F006E007500730005001800000061006E006E00750061006C005F0062 + 006F006E00750073000C000B0000000E001F002000130000002100040000000F + 000110000111000112000113000114000116001800000061006E006E00750061 + 006C005F0062006F006E0075007300220013000000230004000000FEFEFF24FE + FF25FEFF26FF27280000000000FF290000EB0000000000000001001000000052 + 00690063006800610072006400730002000800000052006500650064000300D5 + 0F0B0004001A0000005200650065006400200052006900630068006100720064 + 0073000500FFFF08000C00000070006500720073006F006E00FEFEFF27280001 + 000000FF290000EC0000000000000001000C0000005000610072006B00650072 + 0002000A000000500065007400650072000300D50F0B00040018000000500065 + 0074006500720020005000610072006B00650072000500FFFF08001000000065 + 006D0070006C006F007900650065000900406F400100000000FEFEFF27280002 + 000000FF290000ED0000000000000001000A000000530074006F0072006D0002 + 000600000053007500650003007B010B00040012000000530075006500200053 + 0074006F0072006D000500000008001000000065006D0070006C006F00790065 + 006500090080B14F0100000000FEFEFF27280003000000FF290000EE00000000 + 00000001000C000000420061006E006E006500720002000A0000004200720075 + 0063006500030090010B00040018000000420072007500630065002000420061 + 006E006E00650072000500FFFF08000E0000006D0061006E0061006700650072 + 000900003FAB01000000000A0080F0FA0200000000FEFEFEFEFEFF2AFEFF2B2C + 0004000000FF2DFEFEFE0E004D0061006E0061006700650072001E0055007000 + 6400610074006500730052006500670069007300740072007900120054006100 + 62006C0065004C006900730074000A005400610062006C00650008004E006100 + 6D006500140053006F0075007200630065004E0061006D0065000A0054006100 + 620049004400240045006E0066006F0072006300650043006F006E0073007400 + 7200610069006E00740073001E004D0069006E0069006D0075006D0043006100 + 700061006300690074007900180043006800650063006B004E006F0074004E00 + 75006C006C00140043006F006C0075006D006E004C006900730074000C004300 + 6F006C0075006D006E00100053006F007500720063006500490044000E006400 + 740049006E007400360034001000440061007400610054007900700065001400 + 530065006100720063006800610062006C006500120041006C006C006F007700 + 4E0075006C006C000800420061007300650014004F0041006C006C006F007700 + 4E0075006C006C0012004F0049006E0055007000640061007400650010004F00 + 49006E00570068006500720065000C004F0049006E004B00650079001A004F00 + 72006900670069006E0043006F006C004E0061006D0065001800640074005700 + 69006400650053007400720069006E0067000800530069007A00650014005300 + 6F007500720063006500530069007A0065000C00640074004400610074006500 + 12006400740042006F006F006C00650061006E00140064007400570069006400 + 65004D0065006D006F00100042006C006F00620044006100740061000C006400 + 740042006C006F006200140064007400430075007200720065006E0063007900 + 120050007200650063006900730069006F006E000A005300630061006C006500 + 1E0053006F00750072006300650050007200650063006900730069006F006E00 + 160053006F0075007200630065005300630061006C0065001C0043006F006E00 + 730074007200610069006E0074004C0069007300740010005600690065007700 + 4C006900730074000E0052006F0077004C00690073007400060052006F007700 + 0A0052006F0077004900440010004F0072006900670069006E0061006C001800 + 520065006C006100740069006F006E004C006900730074001C00550070006400 + 61007400650073004A006F00750072006E0061006C0012005300610076006500 + 50006F0069006E0074000E004300680061006E00670065007300} + end +end diff --git a/samples/funcion_actions_showcase/MainDMU.pas b/samples/funcion_actions_showcase/MainDMU.pas new file mode 100644 index 00000000..cb1384b1 --- /dev/null +++ b/samples/funcion_actions_showcase/MainDMU.pas @@ -0,0 +1,26 @@ +unit MainDMU; + +interface + +uses + System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, + FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, + FireDAC.DApt.Intf, FireDAC.Stan.StorageBin, Data.DB, FireDAC.Comp.DataSet, + FireDAC.Comp.Client; + +type + TdmMain = class(TDataModule) + dsPeople: TFDMemTable; + private + { Private declarations } + public + { Public declarations } + end; + +implementation + +{%CLASSGROUP 'System.Classes.TPersistent'} + +{$R *.dfm} + +end. diff --git a/samples/funcion_actions_showcase/function_actions_showcase.dpr b/samples/funcion_actions_showcase/function_actions_showcase.dpr index b2bead95..5d304a46 100644 --- a/samples/funcion_actions_showcase/function_actions_showcase.dpr +++ b/samples/funcion_actions_showcase/function_actions_showcase.dpr @@ -15,7 +15,8 @@ uses IdContext, IdHTTPWebBrokerBridge, ControllerU in 'ControllerU.pas', - WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule}; + WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule}, + MainDMU in 'MainDMU.pas' {dmMain: TDataModule}; {$R *.res} diff --git a/samples/funcion_actions_showcase/function_actions_showcase.dproj b/samples/funcion_actions_showcase/function_actions_showcase.dproj index f27fe07d..98497095 100644 --- a/samples/funcion_actions_showcase/function_actions_showcase.dproj +++ b/samples/funcion_actions_showcase/function_actions_showcase.dproj @@ -120,6 +120,11 @@ dfm TWebModule + +
dmMain
+ dfm + TDataModule +
Base diff --git a/sources/MVCFramework.FireDAC.Utils.pas b/sources/MVCFramework.FireDAC.Utils.pas index d2136f1d..570225f6 100644 --- a/sources/MVCFramework.FireDAC.Utils.pas +++ b/sources/MVCFramework.FireDAC.Utils.pas @@ -29,7 +29,8 @@ unit MVCFramework.FireDAC.Utils; interface uses - FireDAC.Comp.Client, FireDAC.Stan.Param, System.Rtti, JsonDataObjects; + FireDAC.Comp.Client, FireDAC.Stan.Param, System.Rtti, JsonDataObjects, + Data.DB, FireDAC.Comp.DataSet; type TFireDACUtils = class sealed @@ -51,13 +52,13 @@ type TFDCustomMemTableHelper = class helper for TFDCustomMemTable public procedure InitFromMetadata(const AJSONMetadata: TJSONObject); + class function CloneFrom(const FDDataSet: TFDDataSet): TFDMemTable; static; end; implementation uses System.Generics.Collections, - Data.DB, System.Classes, MVCFramework.Serializer.Commons, System.SysUtils; @@ -222,6 +223,12 @@ begin end; end; +class function TFDCustomMemTableHelper.CloneFrom(const FDDataSet: TFDDataSet): TFDMemTable; +begin + Result := TFDMemTable.Create(nil); + TFDMemTable(Result).CloneCursor(FDDataSet); +end; + procedure TFDCustomMemTableHelper.InitFromMetadata(const AJSONMetadata: TJSONObject); begin TFireDACUtils.CreateDatasetFromMetadata(Self, AJSONMetadata); diff --git a/sources/MVCFramework.Serializer.JsonDataObjects.pas b/sources/MVCFramework.Serializer.JsonDataObjects.pas index 141af21e..e6490c0b 100644 --- a/sources/MVCFramework.Serializer.JsonDataObjects.pas +++ b/sources/MVCFramework.Serializer.JsonDataObjects.pas @@ -3034,7 +3034,14 @@ begin begin if Obj <> nil then begin - ObjectToJsonObject(Obj, JSONArray.AddObject, GetSerializationType(Obj, AType), AIgnoredAttributes) + if Obj is TDataSet then + begin + DataSetToJsonArray(TDataSet(Obj), JSONArray.AddArray, TMVCNameCase.ncLowerCase, nil,nil,); + end + else + begin + ObjectToJsonObject(Obj, JSONArray.AddObject, GetSerializationType(Obj, AType), AIgnoredAttributes) + end; end else begin @@ -3074,16 +3081,23 @@ begin begin lJObj := lJSONArr.AddObject; lCurrentArrayItem := ATValueContainingAnArray.GetArrayElement(I); - InternalRecordToJsonObject( - lCurrentArrayItem.GetReferenceToRawData, - lCurrentArrayItem.TypeInfo, - lJObj, - TMVCSerializationType.stFields, - nil, - nil, - nil, - nil - ); + if lCurrentArrayItem.IsObjectInstance then + begin + raise EMVCSerializationException.CreateFmt('Found a "%s" while serializing array. Instance types not allowed in arrays - [HINT] Use list of objects instead of array', [lCurrentArrayItem.AsObject.ClassName]); + end + else + begin + InternalRecordToJsonObject( + lCurrentArrayItem.GetReferenceToRawData, + lCurrentArrayItem.TypeInfo, + lJObj, + TMVCSerializationType.stFields, + nil, + nil, + nil, + nil + ); + end; end; Result := lJSONArr.ToJSON(); finally diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index ea703179..c7ad04f4 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -2515,7 +2515,11 @@ begin lResponseObject := lInvokeResult.AsObject; try // https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0 - if lResponseObject is TStream then + if lResponseObject is TDataSet then + begin + lSelectedController.Render(TDataSet(lResponseObject), False); + end + else if lResponseObject is TStream then begin lContext.Response.RawWebResponse.Content := EmptyStr; lContext.Response.RawWebResponse.ContentType := lContext.Response.ContentType; @@ -2523,16 +2527,13 @@ begin lContext.Response.RawWebResponse.FreeContentStream := True; lResponseObject := nil; //do not free it!! end + else if TDuckTypedList.CanBeWrappedAsList(lResponseObject, lObjList) then + begin + lSelectedController.Render(lObjList); + end else begin - if TDuckTypedList.CanBeWrappedAsList(lResponseObject, lObjList) then - begin - lSelectedController.Render(lObjList); - end - else - begin - lSelectedController.Render(lResponseObject, False); - end; + lSelectedController.Render(lResponseObject, False); end; finally lResponseObject.Free; From 329aaa9190097b36edd4952957e1dcc36cfb63f2 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Wed, 19 Jul 2023 12:29:16 +0200 Subject: [PATCH 09/31] Added more tests on "functional actions" --- ...VCFramework.Serializer.JsonDataObjects.pas | 1 - unittests/general/Several/LiveServerTestU.pas | 102 ++++++++++++++++++ .../TestServer/TestServerControllerU.pas | 67 ++++++++++-- 3 files changed, 161 insertions(+), 9 deletions(-) diff --git a/sources/MVCFramework.Serializer.JsonDataObjects.pas b/sources/MVCFramework.Serializer.JsonDataObjects.pas index e6490c0b..6c6ec09c 100644 --- a/sources/MVCFramework.Serializer.JsonDataObjects.pas +++ b/sources/MVCFramework.Serializer.JsonDataObjects.pas @@ -3794,7 +3794,6 @@ begin raise; end; end; - // lSer.JsonArrayToList(AJsonArray, AList, AClazz, AType, AIgnoredAttributes); finally lSer.Free; end; diff --git a/unittests/general/Several/LiveServerTestU.pas b/unittests/general/Several/LiveServerTestU.pas index 0bc088c4..79ad6e5d 100644 --- a/unittests/general/Several/LiveServerTestU.pas +++ b/unittests/general/Several/LiveServerTestU.pas @@ -298,6 +298,20 @@ type [Test] procedure TestViewDataViewDataSet; + // test functional actions + [Test] + procedure TestFuncActionGetSingleRecord; + + [Test] + procedure TestFuncActionGetMultipleRecords; + + [Test] + procedure TestFuncActionGetDatasetSingle; + + [Test] + procedure TestFuncActionGetDatasetMultiple; + + // test issues [Test] [Category('renders')] @@ -1443,6 +1457,94 @@ begin Assert.areEqual('This is a TEXT file', lRes.Content, '/static/folder1.html'); end; +procedure TServerTest.TestFuncActionGetDatasetMultiple; +var + c1: IMVCRESTClient; + lRes: IMVCRESTResponse; +begin + c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999); + lRes := c1.Get('/api/v1/actionresult/dataset/multiple'); + Assert.areEqual(200, lRes.StatusCode); + var lJSON := lRes.ToJSONObject; + try + Assert.AreEqual(2, lJSON.Count); + Assert.IsTrue(lJSON.Contains('ds1')); + Assert.IsTrue(lJSON.Contains('ds2')); + Assert.AreEqual(15, lJSON.A['ds1'].Count); + Assert.AreEqual(15, lJSON.A['ds2'].Count); + finally + lJSON.Free; + end; +end; + +procedure TServerTest.TestFuncActionGetDatasetSingle; +var + c1: IMVCRESTClient; + lRes: IMVCRESTResponse; +begin + c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999); + lRes := c1.Get('/api/v1/actionresult/dataset/single'); + Assert.areEqual(200, lRes.StatusCode); + var lJSON := lRes.ToJSONArray; + try + Assert.AreEqual(15, lJSON.Count); + for var I := 0 to lJSON.Count - 1 do + begin + Assert.IsTrue(lJSON[I].Typ = jdtObject); + Assert.AreEqual(12, lJSON[I].ObjectValue.Count); + end; + finally + lJSON.Free; + end; +end; + +procedure TServerTest.TestFuncActionGetMultipleRecords; +var + c1: IMVCRESTClient; + lRes: IMVCRESTResponse; +begin + c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999); + lRes := c1.Get('/api/v1/actionresult/records/multiple'); + Assert.areEqual(200, lRes.StatusCode); + var lJSON := lRes.ToJSONArray; + try + Assert.AreEqual(3, lJSON.Count); + + Assert.AreEqual('Daniele', lJSON[0].S['firstName']); + Assert.AreEqual('Teti', lJSON[0].S['lastName']); + Assert.AreEqual(20, lJSON[0].I['age']); + + Assert.AreEqual('Daniele', lJSON[1].S['firstName']); + Assert.AreEqual('Teti', lJSON[1].S['lastName']); + Assert.AreEqual(30, lJSON[1].I['age']); + + Assert.AreEqual('Daniele', lJSON[2].S['firstName']); + Assert.AreEqual('Teti', lJSON[2].S['lastName']); + Assert.AreEqual(40, lJSON[2].I['age']); + finally + lJSON.Free; + end; +end; + +procedure TServerTest.TestFuncActionGetSingleRecord; +var + c1: IMVCRESTClient; + lRes: IMVCRESTResponse; +begin + c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999); + lRes := c1.Get('/api/v1/actionresult/records/single'); + Assert.areEqual(200, lRes.StatusCode); + var lJSON := lRes.ToJSONObject; + try + Assert.AreEqual(3, lJSON.Count); + Assert.AreEqual('Daniele', lJSON.S['firstName']); + Assert.AreEqual('Teti', lJSON.S['lastName']); + Assert.AreEqual(99, lJSON.I['age']); + finally + lJSON.Free; + end; +end; + procedure TServerTest.TestGetImagePng; var c1: IMVCRESTClient; diff --git a/unittests/general/TestServer/TestServerControllerU.pas b/unittests/general/TestServer/TestServerControllerU.pas index 6d000f08..fd7195dd 100644 --- a/unittests/general/TestServer/TestServerControllerU.pas +++ b/unittests/general/TestServer/TestServerControllerU.pas @@ -438,15 +438,29 @@ type property Person: TPerson read FPerson write SetPerson; property People: TPeople read FPeople write SetPeople; end; + + [MVCNameCase(ncCamelCase)] + TPersonRec = record + FirstName, LastName: String; + Age: Integer; + class function Create: TPersonRec; static; + end; // action result types - end [MVCPath('/api/v1/actionresult')] TTestActionResultController = class(TMVCController) public + { actions returning records } [MVCPath('/sums/($a)/($b)')] [MVCHTTPMethod([httpGET])] function GetObject(a,b: Integer): TSum; + [MVCPath('/records/single')] + function GetSingleRecord: TPersonRec; + + [MVCPath('/records/multiple')] + function GetMultipleRecords: TArray; + [MVCPath('/complex')] [MVCHTTPMethod([httpGET])] function GetComplexObject: TComplexObject; @@ -499,9 +513,14 @@ type [MVCHTTPMethod([httpGET])] function GetArrayOfTComplexRecord: TComplexRecordArray; - [MVCPath('/dataset/list')] + [MVCPath('/dataset/single')] [MVCHTTPMethod([httpGET])] - function GetDataSetRecords: TDataSet; + function GetDataSetSingle: TDataSet; + + [MVCPath('/dataset/multiple')] + [MVCHTTPMethod([httpGET])] + function GetDataSetMultiple: IMVCObjectDictionary; + end; @@ -515,7 +534,7 @@ uses Generics.Collections, MVCFramework.Serializer.Defaults, MVCFramework.DuckTyping, - System.IOUtils, MVCFramework.Tests.Serializer.Entities; + System.IOUtils, MVCFramework.Tests.Serializer.Entities, System.DateUtils; { TTestServerController } @@ -1353,7 +1372,15 @@ begin Result.People := TPerson.GetList(); end; -function TTestActionResultController.GetDataSetRecords: TDataSet; +function TTestActionResultController.GetDataSetMultiple: IMVCObjectDictionary; +begin + Result := + ObjectDict() + .Add('ds1', TTestServerController.GetDataSet) + .Add('ds2', TTestServerController.GetDataSet); +end; + +function TTestActionResultController.GetDataSetSingle: TDataSet; begin Result := TTestServerController.GetDataSet; end; @@ -1368,6 +1395,17 @@ begin Result := 3.1415; end; +function TTestActionResultController.GetMultipleRecords: TArray; +begin + SetLength(Result, 3); + Result[0] := TPersonRec.Create; + Result[1] := TPersonRec.Create; + Result[2] := TPersonRec.Create; + Result[0].Age := 20; + Result[1].Age := 30; + Result[2].Age := 40; +end; + function TTestActionResultController.GetPeople: TObjectList; begin Result := TPerson.GetList(); @@ -1375,7 +1413,7 @@ end; function TTestActionResultController.GetPerson(id: Integer): IPerson; begin - Result := TInterfacedPerson.Create('Daniele Teti', 20, 2010); + Result := TInterfacedPerson.Create('Daniele Teti', 20, 2010); end; function TTestActionResultController.GetPhoto: TStream; @@ -1384,6 +1422,11 @@ begin Result := TFileStream.Create('sample.png', fmOpenRead or fmShareDenyNone); end; +function TTestActionResultController.GetSingleRecord: TPersonRec; +begin + Result := TPersonRec.Create; +end; + function TTestActionResultController.GetStrDict: TMVCStringDictionary; begin Result := StrDict.Add('first_name','Daniele').Add('last_name','Teti'); @@ -1407,10 +1450,9 @@ end; function TTestActionResultController.GetObject(a, b: Integer): TSum; begin StatusCode := 201; - Context.Response.SetCustomHeader('X-PIPPO','PLUTO'); + Context.Response.SetCustomHeader('X-CUSTOM-HEADER','CARBONARA'); Result := TSum.Create; - raise Exception.Create('Error Message'); - Result.Value := a+b; + Result.Value := a + b; end; { TComplexObject } @@ -1432,4 +1474,13 @@ begin FPerson := Value; end; +{ TPersonRec } + +class function TPersonRec.Create: TPersonRec; +begin + Result.FirstName := 'Daniele'; + Result.LastName := 'Teti'; + Result.Age := 99; +end; + end. From 7bf4b82db7982433dbcf7255da974489e5d6d5d5 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Wed, 19 Jul 2023 14:35:25 +0200 Subject: [PATCH 10/31] More unit tests for functional actions --- unittests/general/Several/LiveServerTestU.pas | 26 + .../dmvcframework_nunit_win32.xml | 1435 +++++++------- .../dmvcframework_nunit_win64.xml | 1701 +++++++++-------- 3 files changed, 1627 insertions(+), 1535 deletions(-) diff --git a/unittests/general/Several/LiveServerTestU.pas b/unittests/general/Several/LiveServerTestU.pas index 79ad6e5d..f371f3a5 100644 --- a/unittests/general/Several/LiveServerTestU.pas +++ b/unittests/general/Several/LiveServerTestU.pas @@ -311,6 +311,8 @@ type [Test] procedure TestFuncActionGetDatasetMultiple; + [Test] + procedure TestFuncActionGetComplexObject; // test issues [Test] @@ -1457,6 +1459,30 @@ begin Assert.areEqual('This is a TEXT file', lRes.Content, '/static/folder1.html'); end; +procedure TServerTest.TestFuncActionGetComplexObject; +var + c1: IMVCRESTClient; + lRes: IMVCRESTResponse; +begin + c1 := TMVCRESTClient.New.BaseURL(TEST_SERVER_ADDRESS, 9999); + lRes := c1.Get('/api/v1/actionresult/complex'); + Assert.areEqual(200, lRes.StatusCode); + var lJSON := lRes.ToJSONObject; + try + Assert.AreEqual(3, lJSON.Count); + Assert.IsTrue(lJSON.Types['value'] = jdtInt); + Assert.IsTrue(lJSON.Types['person'] = jdtObject); + Assert.IsTrue(lJSON.Types['people'] = jdtArray); + Assert.AreEqual(6, lJSON.O['person'].Count); + Assert.AreEqual(3, lJSON.A['people'].Count); + Assert.AreEqual(6, lJSON.A['people'][0].ObjectValue.Count); + Assert.AreEqual(6, lJSON.A['people'][1].ObjectValue.Count); + Assert.AreEqual(6, lJSON.A['people'][2].ObjectValue.Count); + finally + lJSON.Free; + end; +end; + procedure TServerTest.TestFuncActionGetDatasetMultiple; var c1: IMVCRESTClient; diff --git a/unittests/general/UnitTestReports/dmvcframework_nunit_win32.xml b/unittests/general/UnitTestReports/dmvcframework_nunit_win32.xml index dcb80048..32086969 100644 --- a/unittests/general/UnitTestReports/dmvcframework_nunit_win32.xml +++ b/unittests/general/UnitTestReports/dmvcframework_nunit_win32.xml @@ -1,407 +1,232 @@  - + - + - + - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + - + - - - - - - - - - - + - - + + @@ -409,10 +234,10 @@ - + - - + + @@ -422,19 +247,19 @@ - - - + + + - - + + - + @@ -493,127 +318,282 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -623,387 +603,438 @@ + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - + - + + + + + + + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/unittests/general/UnitTestReports/dmvcframework_nunit_win64.xml b/unittests/general/UnitTestReports/dmvcframework_nunit_win64.xml index df651f92..4575f70e 100644 --- a/unittests/general/UnitTestReports/dmvcframework_nunit_win64.xml +++ b/unittests/general/UnitTestReports/dmvcframework_nunit_win64.xml @@ -1,192 +1,358 @@  - + - + - + - - - - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -199,26 +365,332 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -230,15 +702,211 @@ - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - + + @@ -248,8 +916,8 @@ - - + + @@ -259,17 +927,17 @@ - - + + - + - + @@ -330,212 +998,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + @@ -555,453 +1026,17 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 34bddfc8fd6d147881d532a7d46ae237b157f284 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Thu, 20 Jul 2023 16:40:39 +0200 Subject: [PATCH 11/31] Improved TMVCResponse to better suit the new functional actions --- README.md | 93 ++++++++++++++++++- .../funcion_actions_showcase/ControllerU.pas | 75 +++++++++------ sources/MVCFramework.pas | 38 ++++++-- 3 files changed, 168 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 127e4a18..d56d15d6 100644 --- a/README.md +++ b/README.md @@ -314,10 +314,99 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma Check sample "function_actions_showcase.dproj" for more info. +- ⚡ Improved `TMVCResponse` type to better suits the new functional actions. + + `TMVCResponse` can be used with "message based" responses and also with "data based" responses (with single object or with a list of objects). + + **Message based responses** + + ```pascal + function TMyController.GetMVCResponse: TMVCResponse; + begin + Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', 'My Message'); + end; + ``` + + Produces + + ```json + { + "statuscode":200, + "reasonstring":"My Reason String", + "message":"My Message" + } + ``` + + + + **Data based reponses with single object** + + ```pascal + function TMyController.GetMVCResponse2: TMVCResponse; + begin + Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', TPerson.Create('Daniele','Teti', 99)); + end; + ``` + + Produces + + ```json + { + "statuscode": 200, + "reasonstring": "My Reason String", + "message": "", + "data": { + "firstName": "Daniele", + "lastName": "Teti", + "age": 99 + } + } + ``` + + **Data based reponses with list of objects** + + ```pascal + function TMyController.GetMVCResponse3: TMVCResponse; + begin + Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', + TObjectList.Create([ + TPerson.Create('Daniele','Teti', 99), + TPerson.Create('Peter','Parker', 25), + TPerson.Create('Bruce','Banner', 45) + ]) + ); + end; + ``` + + Produces + + ```json + { + "statuscode": 200, + "reasonstring": "My Reason String", + "message": "", + "data": [ + { + "firstName": "Daniele", + "lastName": "Teti", + "age": 99 + }, + { + "firstName": "Peter", + "lastName": "Parker", + "age": 25 + }, + { + "firstName": "Bruce", + "lastName": "Banner", + "age": 45 + } + ] + } + ``` - -## Hystorical Versions +## Old Versions ### What's New in dmvcframework-3.2.3-radium diff --git a/samples/funcion_actions_showcase/ControllerU.pas b/samples/funcion_actions_showcase/ControllerU.pas index b92051dd..742ba726 100644 --- a/samples/funcion_actions_showcase/ControllerU.pas +++ b/samples/funcion_actions_showcase/ControllerU.pas @@ -23,6 +23,7 @@ type property FirstName: String read fFirstName write fFirstName; property LastName: String read fLastName write fLastName; property Age: Integer read fAge write fAge; + constructor Create(FirstName, LastName: String; Age: Integer); end; [MVCPath('/api')] @@ -57,6 +58,14 @@ type { customize response headers } [MVCPath('/headers')] function GetWithCustomHeaders: TObjectList; + + { using TMVCResponse } + [MVCPath('/mvcresponse/message')] + function GetMVCResponse: TMVCResponse; + [MVCPath('/mvcresponse/data')] + function GetMVCResponse2: TMVCResponse; + [MVCPath('/mvcresponse/list')] + function GetMVCResponse3: TMVCResponse; end; implementation @@ -98,20 +107,11 @@ function TMyController.GetMultipleObjects: TObjectList; begin Result := TObjectList.Create; - Result.Add(TPerson.Create); - Result.Last.FirstName := 'Daniele'; - Result.Last.LastName := 'Teti'; - Result.Last.Age := YearsBetween(Date, EncodeDateDay(1979, 1)); + Result.Add(TPerson.Create('Daniele', 'Teti', YearsBetween(Date, EncodeDateDay(1979, 1)))); - Result.Add(TPerson.Create); - Result.Last.FirstName := 'Daniele'; - Result.Last.LastName := 'Teti'; - Result.Last.Age := Result[0].Age + 10; + Result.Add(TPerson.Create('Daniele', 'Teti', Result[0].Age + 10)); - Result.Add(TPerson.Create); - Result.Last.FirstName := 'Daniele'; - Result.Last.LastName := 'Teti'; - Result.Last.Age := Result[0].Age + 20; + Result.Add(TPerson.Create('Daniele', 'Teti', Result[0].Age + 20)); end; function TMyController.GetMultipleRecords: TArray; @@ -126,6 +126,27 @@ begin Inc(Result[2].Age, 20); end; +function TMyController.GetMVCResponse: TMVCResponse; +begin + Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', 'My Message'); +end; + +function TMyController.GetMVCResponse2: TMVCResponse; +begin + Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', TPerson.Create('Daniele','Teti', 99)); +end; + +function TMyController.GetMVCResponse3: TMVCResponse; +begin + Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', + TObjectList.Create([ + TPerson.Create('Daniele','Teti', 99), + TPerson.Create('Peter','Parker', 25), + TPerson.Create('Bruce','Banner', 45) + ]) + ); +end; + function TMyController.GetSingleDataSet: TDataSet; begin var lDM := TdmMain.Create(nil); @@ -139,10 +160,7 @@ end; function TMyController.GetSingleObject: TPerson; begin - Result := TPerson.Create; - Result.FirstName := 'Daniele'; - Result.LastName := 'Teti'; - Result.Age := YearsBetween(Date, EncodeDateDay(1979, 1)); + Result := TPerson.Create('Daniele', 'Teti', YearsBetween(Date, EncodeDateDay(1979, 1))); end; function TMyController.GetSingleRecord: TPersonRec; @@ -164,20 +182,11 @@ function TMyController.GetWithCustomHeaders: TObjectList; begin Result := TObjectList.Create; - Result.Add(TPerson.Create); - Result.Last.FirstName := 'Daniele'; - Result.Last.LastName := 'Teti'; - Result.Last.Age := YearsBetween(Date, EncodeDateDay(1979, 1)); + Result.Add(TPerson.Create('Daniele', 'Teti', YearsBetween(Date, EncodeDateDay(1979, 1)))); - Result.Add(TPerson.Create); - Result.Last.FirstName := 'Daniele'; - Result.Last.LastName := 'Teti'; - Result.Last.Age := Result[0].Age + 10; + Result.Add(TPerson.Create('Daniele', 'Teti', Result[0].Age + 10)); - Result.Add(TPerson.Create); - Result.Last.FirstName := 'Daniele'; - Result.Last.LastName := 'Teti'; - Result.Last.Age := Result[0].Age + 20; + Result.Add(TPerson.Create('Daniele', 'Teti', Result[0].Age + 20)); { customize headers } Context.Response.StatusCode := HTTP_STATUS.PartialContent; @@ -194,4 +203,14 @@ begin Result.Age := YearsBetween(Date, EncodeDateDay(1979, 1)); end; +{ TPerson } + +constructor TPerson.Create(FirstName, LastName: String; Age: Integer); +begin + inherited Create; + fFirstName := FirstName; + fLastName := LastName; + fAge := Age; +end; + end. diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index c7ad04f4..9f078191 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -1046,15 +1046,17 @@ type [MVCNameCase(ncLowerCase)] TMVCResponse = class private - FStatusCode: Integer; - FReasonString: string; - FMessage: string; + fStatusCode: Integer; + fReasonString: string; + fMessage: string; fDataObject: TObject; protected - { protected declarations } - public constructor Create; overload; virtual; + public constructor Create(AStatusCode: Integer; AReasonString: string; AMessage: string); overload; + constructor Create(AStatusCode: Integer; AMessage: string); overload; + constructor Create(AStatusCode: Integer; AReasonString: string; AData: TObject); overload; + constructor Create(AStatusCode: Integer; AData: TObject); overload; destructor Destroy; override; property StatusCode: Integer read FStatusCode write FStatusCode; property ReasonString: string read FReasonString write FReasonString; @@ -4279,6 +4281,7 @@ constructor TMVCResponse.Create; begin inherited Create; fDataObject := nil; + fMessage := ''; end; constructor TMVCErrorResponse.Create; @@ -4290,9 +4293,28 @@ end; constructor TMVCResponse.Create(AStatusCode: Integer; AReasonString, AMessage: string); begin Create; - StatusCode := AStatusCode; - ReasonString := AReasonString; - message := AMessage; + fStatusCode := AStatusCode; + fReasonString := AReasonString; + fMessage := AMessage; +end; + +constructor TMVCResponse.Create(AStatusCode: Integer; AMessage: string); +begin + Create(AStatusCode, '', AMessage); +end; + +constructor TMVCResponse.Create(AStatusCode: Integer; AReasonString: string; + AData: TObject); +begin + Create; + fStatusCode := AStatusCode; + fReasonString := AReasonString; + fDataObject := AData; +end; + +constructor TMVCResponse.Create(AStatusCode: Integer; AData: TObject); +begin + Create(AStatusCode, '', AData); end; destructor TMVCResponse.Destroy; From 6f8caf88e0989c4c73c0d74f8f19f6b5f6c0c91b Mon Sep 17 00:00:00 2001 From: danieleteti Date: Thu, 20 Jul 2023 14:41:08 +0000 Subject: [PATCH 12/31] chore(docs): update TOC --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d56d15d6..5487e2ab 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ - [What users say about DMVCFramework](#what-users-say-about-dmvcframework) - [What's New in dmvcframework-3.3.0-fluorine (last stable version)](#whats-new-in-dmvcframework-330-fluorine-last-stable-version) - [What's New in the next "repo version" a.k.a. 3.4.0-neon](#whats-new-in-the-next-repo-version-aka-340-neon) - - [Hystorical Versions](#hystorical-versions) + - [Old Versions](#old-versions) - [What's New in dmvcframework-3.2.3-radium](#whats-new-in-dmvcframework-323-radium) - [Bug Fix in 3.2.3-radium](#bug-fix-in-323-radium) - [What's new in DelphiMVCFramework-3.2.2-nitrogen](#whats-new-in-delphimvcframework-322-nitrogen) From 49ed5c782469c2c1ab9f1f894f1e40385895596d Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Thu, 20 Jul 2023 16:47:48 +0200 Subject: [PATCH 13/31] Fixed a default initialization for JWT (thanks to Flavio Basile) --- README.md | 2 ++ sources/MVCFramework.JWT.pas | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d56d15d6..639a7b65 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,8 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma - 🐞 FIX Wrong comparison in checks for ro/RW/PK fields in `TMVCActiveRecord` +- 🐞 FIX wrong default initialization for JWT (thanks to Flavio Basile) + - ⚡ Wizard updated to be dotEnv aware - ⚡ Better error message in case of serialization of `TArray` diff --git a/sources/MVCFramework.JWT.pas b/sources/MVCFramework.JWT.pas index 376447ab..6606bcb9 100644 --- a/sources/MVCFramework.JWT.pas +++ b/sources/MVCFramework.JWT.pas @@ -516,7 +516,7 @@ begin FSecretKey := SecretKey; FRegisteredClaims := TJWTRegisteredClaims.Create; FCustomClaims := TJWTCustomClaims.Create; - FHMACAlgorithm := HMAC_HS512; + FHMACAlgorithm := HMACAlgorithm; FLeewaySeconds := ALeewaySeconds; FRegClaimsToChecks := [TJWTCheckableClaim.ExpirationTime, TJWTCheckableClaim.NotBefore, TJWTCheckableClaim.IssuedAt]; end; From 1d50399b4f6f156d449e6747835e884778be425d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ant=C3=B4nio=20Duarte?= Date: Tue, 25 Jul 2023 15:42:08 -0300 Subject: [PATCH 14/31] Fixed data decompression in TMVCRestClient. On MACOS/iOS clients the decompression is automatic. --- sources/MVCFramework.RESTClient.Commons.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sources/MVCFramework.RESTClient.Commons.pas b/sources/MVCFramework.RESTClient.Commons.pas index c6fa5bb1..747970e5 100644 --- a/sources/MVCFramework.RESTClient.Commons.pas +++ b/sources/MVCFramework.RESTClient.Commons.pas @@ -179,6 +179,9 @@ var begin lDecompressed := TMemoryStream.Create; try +{$IF defined(MACOS) or defined(IOS)} + lDecompressed.CopyFrom(aContentStream, 0); // MACOS automatically decompresses response body +{$ELSE} if SameText(aContentEncoding, 'gzip') or SameText(aContentEncoding, 'deflate') then begin /// Certain types of deflate compression cannot be decompressed by the standard Zlib, @@ -202,6 +205,7 @@ begin begin raise EMVCRESTClientException.CreateFmt('Content-Encoding not supported [%s]', [aContentEncoding]); end; +{$ENDIF} SetLength(Result, lDecompressed.Size); lDecompressed.Position := 0; From 7e451ae1d6808161ad591dd285da4c6c6c1f94da Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Thu, 3 Aug 2023 17:04:28 +0200 Subject: [PATCH 15/31] Added specific rendering case for TMVCResponse and its child classes --- sources/MVCFramework.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index 9f078191..01735b55 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -2529,6 +2529,13 @@ begin lContext.Response.RawWebResponse.FreeContentStream := True; lResponseObject := nil; //do not free it!! end + else if lResponseObject is TMVCResponse then + begin + lSelectedController.ResponseStatus( + TMVCResponse(lResponseObject).StatusCode, + TMVCResponse(lResponseObject).ReasonString); + lSelectedController.Render(TMVCResponse(lResponseObject), False); + end else if TDuckTypedList.CanBeWrappedAsList(lResponseObject, lObjList) then begin lSelectedController.Render(lObjList); From 9b9f2b0a21321f6755f26a659a8342d406d9eaae Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Thu, 3 Aug 2023 17:05:04 +0200 Subject: [PATCH 16/31] Improved CRUD Actions generated by wizard --- .../DMVC.Expert.CodeGen.NewControllerUnit.pas | 23 ++++- ideexpert/DMVC.Expert.CodeGen.Templates.pas | 99 ++++++++++++++----- ideexpert/DMVC.Expert.ProjectWizardEx.pas | 2 +- 3 files changed, 97 insertions(+), 27 deletions(-) diff --git a/ideexpert/DMVC.Expert.CodeGen.NewControllerUnit.pas b/ideexpert/DMVC.Expert.CodeGen.NewControllerUnit.pas index 43108ee1..f9e3d738 100644 --- a/ideexpert/DMVC.Expert.CodeGen.NewControllerUnit.pas +++ b/ideexpert/DMVC.Expert.CodeGen.NewControllerUnit.pas @@ -104,12 +104,19 @@ var lActionFiltersMethodsImpl: string; lCRUDMethodsIntf: string; lCRUDMethodsImpl: string; + lBOClassesIntf: string; + lBOClassesImpl: string; begin lControllerUnit := sControllerUnit; + lIndexMethodIntf := sIndexMethodIntf; lIndexMethodImpl := Format(sIndexMethodImpl, [FControllerClassName]); + lCRUDMethodsIntf := sCRUDMethodsIntf; lCRUDMethodsImpl := Format(sCRUDMethodsImpl, [FControllerClassName]); + lBOClassesIntf := sBOClassesIntf; + lBOClassesImpl := Format(sBOClassesImpl, ['TPerson']); + if not FCreateIndexMethod then begin @@ -121,6 +128,8 @@ begin begin lCRUDMethodsIntf := ''; lCRUDMethodsImpl := ''; + lBOClassesIntf := ''; + lBOClassesImpl := ''; end; lActionFiltersMethodsIntf := sActionFiltersIntf; @@ -138,7 +147,18 @@ begin (BorlandIDEServices as IOTAModuleServices).GetNewModuleAndClassName('', lUnitIdent, lFormName, lFileName); Result := TSourceFile.Create(sControllerUnit, - [lUnitIdent, FControllerClassName, lIndexMethodIntf, lIndexMethodImpl, lActionFiltersMethodsIntf, lActionFiltersMethodsImpl, lCRUDMethodsIntf, lCRUDMethodsImpl]); + [ + lUnitIdent, + FControllerClassName, + lIndexMethodIntf, + lIndexMethodImpl, + lActionFiltersMethodsIntf, + lActionFiltersMethodsImpl, + lCRUDMethodsIntf, + lCRUDMethodsImpl, + lBOClassesIntf, + lBOClassesImpl + ]); end; { TNewJSONRPCUnitEx } @@ -155,7 +175,6 @@ function TNewJSONRPCUnitEx.NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; var lUnitIdent: string; -// lFormName: string; lFileName: string; lDummy: String; begin diff --git a/ideexpert/DMVC.Expert.CodeGen.Templates.pas b/ideexpert/DMVC.Expert.CodeGen.Templates.pas index cf0e927e..21484872 100644 --- a/ideexpert/DMVC.Expert.CodeGen.Templates.pas +++ b/ideexpert/DMVC.Expert.CodeGen.Templates.pas @@ -130,14 +130,18 @@ resourcestring // 3 - Sample Methods - Implementation // 4 - Action Filters - Interface // 5 - Action Filters - Implementation + // 8 - BO - Interface + // 9 - BO - Implementation + sControllerUnit = 'unit %0:s;' + sLineBreak + sLineBreak + 'interface' + sLineBreak + sLineBreak + 'uses' + sLineBreak + - ' MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons;' + sLineBreak + + ' MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons, System.Generics.Collections;' + sLineBreak + sLineBreak + 'type' + sLineBreak + + '%8:s' + sLineBreak + ' [MVCPath(''/api'')]' + sLineBreak + ' %1:s = class(TMVCController) ' + sLineBreak + ' public' + sLineBreak + @@ -154,6 +158,7 @@ resourcestring '%5:s' + sLineBreak + '%7:s' + sLineBreak + sLineBreak + + '%9:s' + sLineBreak + 'end.' + sLineBreak; sIndexMethodIntf = @@ -162,6 +167,7 @@ resourcestring ' procedure Index;' + sLineBreak + sLineBreak + ' [MVCPath(''/reversedstrings/($Value)'')]' + sLineBreak + ' [MVCHTTPMethod([httpGET])]' + sLineBreak + + ' [MVCProduces(TMVCMediaType.TEXT_PLAIN)]' + sLineBreak + ' procedure GetReversedString(const Value: String);' + sLineBreak; // 0 - Class Name @@ -179,45 +185,66 @@ resourcestring sCRUDMethodsIntf = sLineBreak + ' public' + sLineBreak + - ' //Sample CRUD Actions for a "Customer" entity' + sLineBreak + - ' [MVCPath(''/customers'')]' + sLineBreak + + ' //Sample CRUD Actions for a "People" entity' + sLineBreak + + ' [MVCPath(''/people'')]' + sLineBreak + ' [MVCHTTPMethod([httpGET])]' + sLineBreak + - ' procedure GetCustomers;' + sLineBreak + sLineBreak + - ' [MVCPath(''/customers/($id)'')]' + sLineBreak + + ' function GetPeople: TObjectList;' + sLineBreak + sLineBreak + + ' [MVCPath(''/people/($ID)'')]' + sLineBreak + ' [MVCHTTPMethod([httpGET])]' + sLineBreak + - ' procedure GetCustomer(id: Integer);' + sLineBreak + sLineBreak + - ' [MVCPath(''/customers'')]' + sLineBreak + + ' function GetPerson(ID: Integer): TPerson;' + sLineBreak + sLineBreak + + ' [MVCPath(''/people'')]' + sLineBreak + ' [MVCHTTPMethod([httpPOST])]' + sLineBreak + - ' procedure CreateCustomer;' + sLineBreak + sLineBreak + - ' [MVCPath(''/customers/($id)'')]' + sLineBreak + + ' function CreatePerson([MVCFromBody] Person: TPerson): TMVCResponse;' + sLineBreak + sLineBreak + + ' [MVCPath(''/people/($ID)'')]' + sLineBreak + ' [MVCHTTPMethod([httpPUT])]' + sLineBreak + - ' procedure UpdateCustomer(id: Integer);' + sLineBreak + sLineBreak + - ' [MVCPath(''/customers/($id)'')]' + sLineBreak + + ' function UpdatePerson(ID: Integer; [MVCFromBody] Person: TPerson): TMVCResponse;' + sLineBreak + sLineBreak + + ' [MVCPath(''/people/($ID)'')]' + sLineBreak + ' [MVCHTTPMethod([httpDELETE])]' + sLineBreak + - ' procedure DeleteCustomer(id: Integer);' + sLineBreak + sLineBreak; + ' function DeletePerson(ID: Integer): TMVCResponse;' + sLineBreak + sLineBreak; sCRUDMethodsImpl = - '//Sample CRUD Actions for a "Customer" entity' + sLineBreak + - 'procedure %0:s.GetCustomers;' + sLineBreak + + '//Sample CRUD Actions for a "People" entity' + sLineBreak + + 'function %0:s.GetPeople: TObjectList;' + sLineBreak + + 'var' + sLineBreak + + ' lPeople: TObjectList;' + sLineBreak + 'begin' + sLineBreak + - ' //todo: render a list of customers' + sLineBreak + + ' lPeople := TObjectList.Create(True);' + sLineBreak + + ' try' + sLineBreak + + ' lPeople.Add(TPerson.Create(''Peter'',''Parker'', EncodeDate(1965, 10, 4)));' + sLineBreak + + ' lPeople.Add(TPerson.Create(''Bruce'',''Banner'', EncodeDate(1945, 9, 6)));' + sLineBreak + + ' lPeople.Add(TPerson.Create(''Reed'',''Richards'', EncodeDate(1955, 3, 7)));' + sLineBreak + + ' Result := lPeople;' + sLineBreak + + ' except' + sLineBreak + + ' lPeople.Free;' + sLineBreak + + ' raise;' + sLineBreak + + ' end;' + sLineBreak + 'end;' + sLineBreak + sLineBreak + - 'procedure %0:s.GetCustomer(id: Integer);' + sLineBreak + + 'function %0:s.GetPerson(ID: Integer): TPerson;' + sLineBreak + + 'var' + sLineBreak + + ' lPeople: TObjectList;' + sLineBreak + 'begin' + sLineBreak + - ' //todo: render the customer by id' + sLineBreak + + ' lPeople := GetPeople;' + sLineBreak + + ' try' + sLineBreak + + ' Result := lPeople.ExtractAt(ID mod lPeople.Count);' + sLineBreak + + ' finally' + sLineBreak + + ' lPeople.Free;' + sLineBreak + + ' end;' + sLineBreak + 'end;' + sLineBreak + sLineBreak + - 'procedure %0:s.CreateCustomer;' + sLineBreak + + 'function %0:s.CreatePerson([MVCFromBody] Person: TPerson): TMVCResponse;' + sLineBreak + 'begin' + sLineBreak + - ' //todo: create a new customer' + sLineBreak + + ' LogI(''Created '' + Person.FirstName + '' '' + Person.LastName);' + sLineBreak + + ' Result := TMVCResponse.Create(HTTP_STATUS.Created, ''Person created'');' + sLineBreak + 'end;' + sLineBreak + sLineBreak + - 'procedure %0:s.UpdateCustomer(id: Integer);' + sLineBreak + + 'function %0:s.UpdatePerson(ID: Integer; [MVCFromBody] Person: TPerson): TMVCResponse;' + sLineBreak + 'begin' + sLineBreak + - ' //todo: update customer by id' + sLineBreak + + ' LogI(''Updated '' + Person.FirstName + '' '' + Person.LastName);' + sLineBreak + + ' Result := TMVCResponse.Create(HTTP_STATUS.OK, ''Person updated'');' + sLineBreak + 'end;' + sLineBreak + sLineBreak + - 'procedure %0:s.DeleteCustomer(id: Integer);' + sLineBreak + + 'function %0:s.DeletePerson(ID: Integer): TMVCResponse;' + sLineBreak + 'begin' + sLineBreak + - ' //todo: delete customer by id' + sLineBreak + - 'end;' + sLineBreak + sLineBreak; + ' LogI(''Deleted person with id '' + ID.ToString);' + sLineBreak + + ' Result := TMVCResponse.Create(HTTP_STATUS.OK, ''Person deleted'');' + sLineBreak + + 'end;' + sLineBreak; sActionFiltersIntf = ' protected' + sLineBreak + @@ -242,6 +269,30 @@ resourcestring ' inherited;' + sLineBreak + 'end;' + sLineBreak; + sBOClassesIntf = + ' [MVCNameCase(ncCamelCase)]' + sLineBreak + + ' TPerson = class' + sLineBreak + + ' private' + sLineBreak + + ' fFirstName: String;' + sLineBreak + + ' fLastName: String;' + sLineBreak + + ' fDOB: TDate;' + sLineBreak + + ' public' + sLineBreak + + ' property FirstName: String read fFirstName write fFirstName;' + sLineBreak + + ' property LastName: String read fLastName write fLastName;' + sLineBreak + + ' property DOB: TDate read fDOB write fDOB; ' + sLineBreak + + ' constructor Create(FirstName, LastName: String; DOB: TDate);' + sLineBreak + + ' end;' + sLineBreak; + + sBOClassesImpl = + sLineBreak + + 'constructor %0:s.Create(FirstName, LastName: String; DOB: TDate);' + sLineBreak + + 'begin' + sLineBreak + + ' inherited Create;' + sLineBreak + + ' fFirstName := FirstName;' + sLineBreak + + ' fLastName := LastName;' + sLineBreak + + ' fDOB := DOB;' + sLineBreak + + 'end;' + sLineBreak; + sDefaultControllerName = 'TMyController'; sDefaultWebModuleName = 'TMyWebModule'; sDefaultServerPort = '8080'; diff --git a/ideexpert/DMVC.Expert.ProjectWizardEx.pas b/ideexpert/DMVC.Expert.ProjectWizardEx.pas index f7c70f05..b9661e01 100644 --- a/ideexpert/DMVC.Expert.ProjectWizardEx.pas +++ b/ideexpert/DMVC.Expert.ProjectWizardEx.pas @@ -94,7 +94,7 @@ begin JSONRPCUnitCreator: IOTACreator; WebModuleCreator: IOTAModuleCreator; lProjectSourceCreator: IOTACreator; - lJSONRPCUnitName: string; + lJSONRPCUnitName: string; begin WizardForm := TfrmDMVCNewProject.Create(Application); try From 8631a155ff922dea32c47aeccac49e95861c31b5 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Fri, 4 Aug 2023 13:09:05 +0200 Subject: [PATCH 17/31] - Added IMVCResponse with related helper methods "MVCResponse(...)" - IMVCObjectDictionary can be serialized as attribute and not only as root object (required to serialize IMVCObjectDictionary from TMVCResponse) --- .../funcion_actions_showcase/ControllerU.pas | 50 ++++- ...Serializer.JsonDataObjects.CustomTypes.pas | 46 +++-- sources/MVCFramework.pas | 193 +++++++++++++++--- 3 files changed, 232 insertions(+), 57 deletions(-) diff --git a/samples/funcion_actions_showcase/ControllerU.pas b/samples/funcion_actions_showcase/ControllerU.pas index 742ba726..8fb632d3 100644 --- a/samples/funcion_actions_showcase/ControllerU.pas +++ b/samples/funcion_actions_showcase/ControllerU.pas @@ -59,13 +59,17 @@ type [MVCPath('/headers')] function GetWithCustomHeaders: TObjectList; - { using TMVCResponse } + { using IMVCResponse } [MVCPath('/mvcresponse/message')] - function GetMVCResponse: TMVCResponse; + function GetMVCResponseSimple: IMVCResponse; [MVCPath('/mvcresponse/data')] - function GetMVCResponse2: TMVCResponse; + function GetMVCResponseWithData: IMVCResponse; [MVCPath('/mvcresponse/list')] - function GetMVCResponse3: TMVCResponse; + function GetMVCResponseWithObjectList: IMVCResponse; + [MVCPath('/mvcresponse/dictionary')] + function GetMVCResponseWithObjectDictionary: IMVCResponse; + [MVCPath('/mvcresponse/error')] + function GetMVCErrorResponse: IMVCResponse; end; implementation @@ -126,19 +130,45 @@ begin Inc(Result[2].Age, 20); end; -function TMyController.GetMVCResponse: TMVCResponse; +function TMyController.GetMVCErrorResponse: IMVCResponse; begin - Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', 'My Message'); + Result := TMVCErrorResponse.Create(500, 'boom'); end; -function TMyController.GetMVCResponse2: TMVCResponse; +function TMyController.GetMVCResponseSimple: IMVCResponse; begin - Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', TPerson.Create('Daniele','Teti', 99)); + Result := MVCResponse(HTTP_STATUS.OK, 'My Message', 'My Reason String'); end; -function TMyController.GetMVCResponse3: TMVCResponse; +function TMyController.GetMVCResponseWithData: IMVCResponse; begin - Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', + Result := MVCResponse(HTTP_STATUS.OK, TPerson.Create('Daniele','Teti', 99)); +end; + +function TMyController.GetMVCResponseWithObjectDictionary: IMVCResponse; +begin + Result := MVCResponse( + HTTP_STATUS.OK, + ObjectDict() + .Add('people1', TObjectList.Create([ + TPerson.Create('Daniele','Teti', 99), + TPerson.Create('Peter','Parker', 25), + TPerson.Create('Bruce','Banner', 45) + ]) + ) + .Add('people2', TObjectList.Create([ + TPerson.Create('Daniele','Teti', 99), + TPerson.Create('Peter','Parker', 25), + TPerson.Create('Bruce','Banner', 45) + ]) + ) + ); +end; + +function TMyController.GetMVCResponseWithObjectList: IMVCResponse; +begin + Result := MVCResponse( + HTTP_STATUS.OK, TObjectList.Create([ TPerson.Create('Daniele','Teti', 99), TPerson.Create('Peter','Parker', 25), diff --git a/sources/MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas b/sources/MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas index 1b7a97d8..f55fab67 100644 --- a/sources/MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas +++ b/sources/MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas @@ -72,6 +72,11 @@ type end; TMVCObjectDictionarySerializer = class(TInterfacedObject, IMVCTypeSerializer) + private + procedure InternalSerializeIMVCObjectDictionary( + lObjDict: TMVCObjectDictionary; + var lOutObject: TJsonObject; + const ASerializationAction: TMVCSerializationAction); protected fCurrentSerializer: TMVCJsonDataObjectsSerializer; public @@ -469,27 +474,28 @@ procedure TMVCObjectDictionarySerializer.SerializeAttribute( const AElementValue: TValue; const APropertyName: string; const ASerializerObject: TObject; const AAttributes: TArray); -begin - raise EMVCDeserializationException.Create('Serialization as attribute not supported for this type'); -end; - -procedure TMVCObjectDictionarySerializer.SerializeRoot(const AObject: TObject; - out ASerializerObject: TObject; const AAttributes: TArray; - const ASerializationAction: TMVCSerializationAction); var lObjDict: TMVCObjectDictionary; - lOutObject, lOutCustom: TJsonObject; + lOutObject: TJsonObject; +begin + lObjDict := TMVCObjectDictionary(AElementValue.AsInterface); + lOutObject := TJsonObject(ASerializerObject); + InternalSerializeIMVCObjectDictionary(lObjDict, lOutObject, nil); +end; + +procedure TMVCObjectDictionarySerializer.InternalSerializeIMVCObjectDictionary( + lObjDict: TMVCObjectDictionary; + var lOutObject: TJsonObject; + const ASerializationAction: TMVCSerializationAction); +var + lOutCustom: TJsonObject; lName: string; lObj: TMVCObjectDictionary.TMVCObjectDictionaryValueItem; lList: IMVCList; lLinks: IMVCLinks; lJSONType: TJsonDataType; lJSONValue: TJsonBaseObject; - begin - lObjDict := TMVCObjectDictionary(AObject); - lOutObject := TJsonObject.Create; - try for lName in lObjDict.Keys do begin lObj := lObjDict.Items[lName]; @@ -585,10 +591,22 @@ begin RaiseSerializationError('Invalid JSON'); end; end; - // fCurrentSerializer.InternalObjectToJsonObject(lObj.Data, lOutObject.O[lName], - // TMVCSerializationType.stDefault, [], lObj.SerializationAction, lLinks, nil); end; end + +end; + +procedure TMVCObjectDictionarySerializer.SerializeRoot(const AObject: TObject; + out ASerializerObject: TObject; const AAttributes: TArray; + const ASerializationAction: TMVCSerializationAction); +var + lObjDict: TMVCObjectDictionary; + lOutObject: TJsonObject; +begin + lObjDict := TMVCObjectDictionary(AObject); + lOutObject := TJsonObject.Create; + try + InternalSerializeIMVCObjectDictionary(lObjDict, lOutObject, ASerializationAction); except lOutObject.Free; raise; diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index 01735b55..1abe66bd 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -1043,45 +1043,77 @@ type property message: string read FMessage write FMessage; end; + + // std responses + + IMVCResponse = interface + ['{9DFEC741-EE38-4AC9-9C2C-9EA0D15D08D5}'] + function GetData: TObject; + function GetMessage: string; + function GetReasonString: string; + function GetStatusCode: Integer; + function GetIgnoredList: TMVCIgnoredList; + property StatusCode: Integer read GetStatusCode; + property ReasonString: string read GetReasonString; + property Message: string read GetMessage; + property Data: TObject read GetData; + end; + [MVCNameCase(ncLowerCase)] - TMVCResponse = class + TMVCResponse = class(TInterfacedObject, IMVCResponse) private fStatusCode: Integer; fReasonString: string; fMessage: string; fDataObject: TObject; + fIgnoredList: TMVCIgnoredList; + fObjectDictionary: IMVCObjectDictionary; + function GetData: TObject; + function GetMessage: string; + function GetReasonString: string; + function GetStatusCode: Integer; + procedure SetData(const Value: TObject); + procedure SetMessage(const Value: string); + procedure SetReasonString(const Value: string); + procedure SetStatusCode(const Value: Integer); + function GetObjectDictionary: IMVCObjectDictionary; + procedure SetObjectDictionary(const Value: IMVCObjectDictionary); protected constructor Create; overload; virtual; public - constructor Create(AStatusCode: Integer; AReasonString: string; AMessage: string); overload; - constructor Create(AStatusCode: Integer; AMessage: string); overload; - constructor Create(AStatusCode: Integer; AReasonString: string; AData: TObject); overload; - constructor Create(AStatusCode: Integer; AData: TObject); overload; + constructor Create(AStatusCode: Integer; AMessage: string; AReasonString: string = ''); overload; + constructor Create(AStatusCode: Integer; AData: TObject; AReasonString: string = ''); overload; + constructor Create(AStatusCode: Integer; AObjectDictionary: IMVCObjectDictionary; AReasonString: 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; - property Data: TObject read fDataObject write fDataObject; + function GetIgnoredList: TMVCIgnoredList; + [MVCDoNotSerialize] + property StatusCode: Integer read GetStatusCode write SetStatusCode; + [MVCDoNotSerialize] + property ReasonString: string read GetReasonString write SetReasonString; + property Message: string read GetMessage write SetMessage; + property Data: TObject read GetData write SetData; + property ObjectDictionary: IMVCObjectDictionary read GetObjectDictionary write SetObjectDictionary; end; [MVCNameCase(ncLowerCase)] TMVCErrorResponse = class(TMVCResponse) private - FClassname: string; - FItems: TObjectList; - FAppErrorCode: Integer; - FDetailedMessage: string; + fClassname: string; + fItems: TObjectList; + fAppErrorCode: Integer; + fDetailedMessage: string; procedure SetAppErrorCode(const Value: Integer); public constructor Create; override; destructor Destroy; override; - property Classname: string read FClassname write FClassname; - property DetailedMessage: string read FDetailedMessage write FDetailedMessage; - property AppErrorCode: Integer read FAppErrorCode write SetAppErrorCode; + property Classname: string read fClassname write fClassname; + property DetailedMessage: string read fDetailedMessage write fDetailedMessage; + property AppErrorCode: Integer read fAppErrorCode write SetAppErrorCode; [MVCListOf(TMVCErrorResponseItem)] - property Items: TObjectList read FItems; + property Items: TObjectList read fItems; end; + // end - std responses TMVCBaseViewEngine = class(TMVCBase) @@ -1116,7 +1148,13 @@ type function IsShuttingDown: Boolean; procedure EnterInShutdownState; function CreateResponse(const StatusCode: UInt16; const ReasonString: string; - const Message: string = ''): TMVCResponse; + const Message: string = ''): TMVCResponse; deprecated 'Use MVCResponse()'; + +// std responses +function MVCResponse(AStatusCode: Integer; AMessage: string = ''; AReasonString: string = ''): IMVCResponse; overload; +function MVCResponse(AStatusCode: Integer; AData: TObject; AReasonString: string = ''): IMVCResponse; overload; +function MVCResponse(AStatusCode: Integer; AObjectDictionary: IMVCObjectDictionary; AReasonString: string = ''): IMVCResponse; overload; +// end - std responses implementation @@ -2510,7 +2548,18 @@ begin case lInvokeResult.Kind of tkInterface: begin - lSelectedController.Render(lInvokeResult.AsInterface); + if Supports(lInvokeResult.AsInterface, IMVCResponse) then + begin + lResponseObject := TMVCResponse(lInvokeResult.AsInterface); + lSelectedController.ResponseStatus( + TMVCResponse(lResponseObject).StatusCode, + TMVCResponse(lResponseObject).ReasonString); + lSelectedController.Render(TMVCResponse(lResponseObject), False); + end + else + begin + lSelectedController.Render(lInvokeResult.AsInterface); + end; end; tkClass: begin @@ -4237,8 +4286,8 @@ begin begin try GetContext.Response.StatusCode := AResponse.StatusCode; - GetContext.Response.ReasonString := HTTP_STATUS.ReasonStringFor(AResponse.StatusCode); - Render(AResponse, False, stProperties); + GetContext.Response.ReasonString := AResponse.ReasonString; + Render(AResponse, False, stProperties, nil, AResponse.GetIgnoredList); finally if AOwns then AResponse.Free; @@ -4297,31 +4346,32 @@ begin FItems := TObjectList.Create(True); end; -constructor TMVCResponse.Create(AStatusCode: Integer; AReasonString, AMessage: string); +constructor TMVCResponse.Create(AStatusCode: Integer; AMessage: string; AReasonString: string); begin Create; fStatusCode := AStatusCode; - fReasonString := AReasonString; fMessage := AMessage; + fReasonString := AReasonString; + fIgnoredList := ['Data', 'ObjectDictionary']; end; -constructor TMVCResponse.Create(AStatusCode: Integer; AMessage: string); -begin - Create(AStatusCode, '', AMessage); -end; - -constructor TMVCResponse.Create(AStatusCode: Integer; AReasonString: string; - AData: TObject); +constructor TMVCResponse.Create(AStatusCode: Integer; AData: TObject; AReasonString: string); begin Create; fStatusCode := AStatusCode; - fReasonString := AReasonString; fDataObject := AData; + fReasonString := AReasonString; + fIgnoredList := ['Message', 'ObjectDictionary']; end; -constructor TMVCResponse.Create(AStatusCode: Integer; AData: TObject); +constructor TMVCResponse.Create(AStatusCode: Integer; + AObjectDictionary: IMVCObjectDictionary; AReasonString: string); begin - Create(AStatusCode, '', AData); + Create; + fStatusCode := AStatusCode; + fObjectDictionary := AObjectDictionary; + fReasonString := AReasonString; + fIgnoredList := ['Message', 'Data']; end; destructor TMVCResponse.Destroy; @@ -4330,6 +4380,64 @@ begin inherited; end; +function TMVCResponse.GetData: TObject; +begin + Result := fDataObject; +end; + +function TMVCResponse.GetIgnoredList: TMVCIgnoredList; +begin + Result := fIgnoredList; +end; + +function TMVCResponse.GetMessage: string; +begin + Result := fMessage; +end; + +function TMVCResponse.GetObjectDictionary: IMVCObjectDictionary; +begin + Result := fObjectDictionary; +end; + +function TMVCResponse.GetReasonString: string; +begin + if fReasonString.IsEmpty then + Result := HTTP_STATUS.ReasonStringFor(fStatusCode) + else + Result := fReasonString; +end; + +function TMVCResponse.GetStatusCode: Integer; +begin + Result := fStatusCode; +end; + +procedure TMVCResponse.SetData(const Value: TObject); +begin + fDataObject := Value; +end; + +procedure TMVCResponse.SetMessage(const Value: string); +begin + fMessage := Value; +end; + +procedure TMVCResponse.SetObjectDictionary(const Value: IMVCObjectDictionary); +begin + fObjectDictionary := Value; +end; + +procedure TMVCResponse.SetReasonString(const Value: string); +begin + fReasonString := Value; +end; + +procedure TMVCResponse.SetStatusCode(const Value: Integer); +begin + fStatusCode := Value; +end; + destructor TMVCErrorResponse.Destroy; begin FItems.Free; @@ -4432,6 +4540,25 @@ begin FFormat := AFormat; end; +// std responses +function MVCResponse(AStatusCode: Integer; AMessage: string; AReasonString: string): IMVCResponse; overload; +begin + Result := TMVCResponse.Create(AStatusCode, AMessage, AReasonString); +end; + +function MVCResponse(AStatusCode: Integer; AData: TObject; AReasonString: string): IMVCResponse; overload; +begin + Result := TMVCResponse.Create(AStatusCode, AData, AReasonString); +end; + +function MVCResponse(AStatusCode: Integer; AObjectDictionary: IMVCObjectDictionary; AReasonString: string): IMVCResponse; overload; +begin + Result := TMVCResponse.Create(AStatusCode, AObjectDictionary, AReasonString); +end; + +// end - std responses + + initialization // https://quality.embarcadero.com/browse/RSP-38281 From 4a27f8b64d8f5f8633d0554064778989f24b737e Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Fri, 4 Aug 2023 14:34:42 +0200 Subject: [PATCH 18/31] - Updated unittest with the new TMVCResponse behavior --- README.md | 90 +++++++++++++++---- unittests/general/Several/LiveServerTestU.pas | 12 +-- 2 files changed, 78 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 172ba950..e8f92326 100644 --- a/README.md +++ b/README.md @@ -318,14 +318,14 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma - ⚡ Improved `TMVCResponse` type to better suits the new functional actions. - `TMVCResponse` can be used with "message based" responses and also with "data based" responses (with single object or with a list of objects). + `TMVCResponse` can be used with "message based" responses and also with "data based" responses (with single object, with a list of objects or with a dictionary of objects). **Message based responses** ```pascal function TMyController.GetMVCResponse: TMVCResponse; begin - Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', 'My Message'); + Result := MVCResponse(HTTP_STATUS.OK, 'My Message'); end; ``` @@ -333,20 +333,18 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma ```json { - "statuscode":200, - "reasonstring":"My Reason String", "message":"My Message" } ``` + + - - - **Data based reponses with single object** + **Data based response with single object** ```pascal function TMyController.GetMVCResponse2: TMVCResponse; begin - Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', TPerson.Create('Daniele','Teti', 99)); + Result := MVCResponse(HTTP_STATUS.OK, TPerson.Create('Daniele','Teti', 99)); end; ``` @@ -354,9 +352,6 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma ```json { - "statuscode": 200, - "reasonstring": "My Reason String", - "message": "", "data": { "firstName": "Daniele", "lastName": "Teti", @@ -365,12 +360,12 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma } ``` - **Data based reponses with list of objects** + **Data based response with list of objects** ```pascal function TMyController.GetMVCResponse3: TMVCResponse; begin - Result := TMVCResponse.Create(HTTP_STATUS.OK, 'My Reason String', + Result := MVCResponse(HTTP_STATUS.OK, TObjectList.Create([ TPerson.Create('Daniele','Teti', 99), TPerson.Create('Peter','Parker', 25), @@ -384,9 +379,6 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma ```json { - "statuscode": 200, - "reasonstring": "My Reason String", - "message": "", "data": [ { "firstName": "Daniele", @@ -407,6 +399,72 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma } ``` + **Data dictionary based response with `IMVCObjectDictionary` ** + + ```pascal + function TMyController.GetMVCResponseWithObjectDictionary: IMVCResponse; + begin + Result := MVCResponse( + HTTP_STATUS.OK, + ObjectDict() + .Add('employees', TObjectList.Create([ + TPerson.Create('Daniele','Teti', 99), + TPerson.Create('Peter','Parker', 25), + TPerson.Create('Bruce','Banner', 45) + ]) + ) + .Add('customers', TObjectList.Create([ + TPerson.Create('Daniele','Teti', 99), + TPerson.Create('Peter','Parker', 25), + TPerson.Create('Bruce','Banner', 45) + ]) + ) + ); + end; + ``` + + Produces + + ```json + { + "employees": [ + { + "firstName": "Daniele", + "lastName": "Teti", + "age": 99 + }, + { + "firstName": "Peter", + "lastName": "Parker", + "age": 25 + }, + { + "firstName": "Bruce", + "lastName": "Banner", + "age": 45 + } + ], + "customers": [ + { + "firstName": "Daniele", + "lastName": "Teti", + "age": 99 + }, + { + "firstName": "Peter", + "lastName": "Parker", + "age": 25 + }, + { + "firstName": "Bruce", + "lastName": "Banner", + "age": 45 + } + ] + } + ``` + +- Removed `statuscode` and `reasonstring` from exception's JSON rendering. ## Old Versions diff --git a/unittests/general/Several/LiveServerTestU.pas b/unittests/general/Several/LiveServerTestU.pas index f371f3a5..eefa9163 100644 --- a/unittests/general/Several/LiveServerTestU.pas +++ b/unittests/general/Several/LiveServerTestU.pas @@ -1084,12 +1084,11 @@ var begin res := RESTClient.Get('/exception/emvcexception1'); Assert.areEqual(HTTP_STATUS.InternalServerError, res.StatusCode); + Assert.areEqual('Internal Server Error', res.StatusText); lJSON := StrToJSONObject(res.Content); try 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('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 @@ -1105,12 +1104,11 @@ var begin res := RESTClient.Get('/exception/emvcexception2'); Assert.areEqual(HTTP_STATUS.BadRequest, res.StatusCode); + Assert.areEqual('Bad Request', res.StatusText); lJSON := StrToJSONObject(res.Content); try 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('Bad Request', lJSON.S['reasonstring'], lJSON.ToJSON()); Assert.areEqual(0, lJSON.A['items'].Count, lJSON.ToJSON()); Assert.isTrue(lJSON.IsNull('data'), lJSON.ToJSON()); finally @@ -1125,12 +1123,11 @@ var begin res := RESTClient.Get('/exception/emvcexception3'); Assert.areEqual(HTTP_STATUS.Created, res.StatusCode); + Assert.areEqual('Created', res.StatusText); lJSON := StrToJSONObject(res.Content); try 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('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()); @@ -1146,13 +1143,12 @@ var begin res := RESTClient.Get('/exception/emvcexception4'); Assert.areEqual(HTTP_STATUS.Created, res.StatusCode); + Assert.areEqual('Created', res.StatusText); lJSON := StrToJSONObject(res.Content); try Assert.areEqual('message', lJSON.S['message'], lJSON.ToJSON()); 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('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()); From c201c916cbb7ffc8b72090b14b11d1f326ac9184 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Tue, 8 Aug 2023 14:31:23 +0200 Subject: [PATCH 19/31] https://github.com/danieleteti/delphimvcframework/issues/675 --- README.md | 2 + samples/activerecord_showcase/MainFormU.dfm | 331 +++++++------------- samples/activerecord_showcase/MainFormU.pas | 109 +++++++ sources/MVCFramework.ActiveRecord.pas | 236 ++++++++++---- 4 files changed, 403 insertions(+), 275 deletions(-) diff --git a/README.md b/README.md index e8f92326..e8e83105 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,8 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma - ⚡ Wizard updated to be dotEnv aware +- ⚡ Added "Load Style" methods to `TMVCActiveRecord` as suggested by https://github.com/danieleteti/delphimvcframework/issues/675 + - ⚡ Better error message in case of serialization of `TArray` - ⚡ Improved serialization of `TObjectList` (however `ObjectDict` is still the preferred way to serialize multiple datasets). diff --git a/samples/activerecord_showcase/MainFormU.dfm b/samples/activerecord_showcase/MainFormU.dfm index 5a2196ec..5d1aeb54 100644 --- a/samples/activerecord_showcase/MainFormU.dfm +++ b/samples/activerecord_showcase/MainFormU.dfm @@ -2,62 +2,49 @@ object MainForm: TMainForm Left = 0 Top = 0 Caption = 'TMVCActiveRecord - ShowCase' - ClientHeight = 1423 - ClientWidth = 2760 + ClientHeight = 569 + ClientWidth = 1104 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText - Font.Height = -28 + Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OnDestroy = FormDestroy OnShow = FormShow - PixelsPerInch = 240 DesignSize = ( - 2760 - 1423) - TextHeight = 34 + 1104 + 569) + TextHeight = 13 object btnCRUD: TButton - Left = 20 - Top = 20 - Width = 303 - Height = 83 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 8 + Width = 121 + Height = 33 Caption = 'CRUD' TabOrder = 0 OnClick = btnCRUDClick end object btnSelect: TButton - Left = 20 - Top = 605 - Width = 303 - Height = 83 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 242 + Width = 121 + Height = 33 Caption = 'Queries' TabOrder = 1 OnClick = btnSelectClick end object Memo1: TMemo - Left = 700 - Top = 20 - Width = 2040 - Height = 1383 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 280 + Top = 8 + Width = 816 + Height = 553 Anchors = [akLeft, akTop, akRight, akBottom] Ctl3D = True DoubleBuffered = True Font.Charset = ANSI_CHARSET Font.Color = clWindowText - Font.Height = -33 + Font.Height = -13 Font.Name = 'Consolas' Font.Style = [] ParentCtl3D = False @@ -68,306 +55,214 @@ object MainForm: TMainForm TabOrder = 2 WantReturns = False WordWrap = False - ExplicitWidth = 2020 - ExplicitHeight = 1381 + ExplicitWidth = 812 + ExplicitHeight = 552 end object btnRelations: TButton - Left = 20 - Top = 703 - Width = 303 - Height = 87 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 281 + Width = 121 + Height = 35 Caption = 'Relations' TabOrder = 3 OnClick = btnRelationsClick end object btnInheritance: TButton - Left = 20 - Top = 805 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 322 + Width = 121 + Height = 34 Caption = 'Inheritance' TabOrder = 4 OnClick = btnInheritanceClick end object btnValidation: TButton - Left = 20 - Top = 905 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 362 + Width = 121 + Height = 34 Caption = 'Validation' TabOrder = 5 OnClick = btnValidationClick end object btnMultiThreading: TButton - Left = 360 - Top = 20 - Width = 303 - Height = 83 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 8 + Width = 121 + Height = 33 Caption = 'Multi Threading' TabOrder = 6 OnClick = btnMultiThreadingClick end object btnRQL: TButton - Left = 20 - Top = 1005 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 402 + Width = 121 + Height = 34 Caption = 'RQL Query' TabOrder = 7 OnClick = btnRQLClick end object btnReadOnlyFields: TButton - Left = 20 - Top = 508 - Width = 303 - Height = 82 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 203 + Width = 121 + Height = 33 Caption = 'CRUD With R/O Field' TabOrder = 8 OnClick = btnReadOnlyFieldsClick end object btnNullTest: TButton - Left = 360 - Top = 118 - Width = 303 - Height = 82 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 47 + Width = 121 + Height = 33 Caption = 'Nullables' TabOrder = 9 OnClick = btnNullTestClick end object btnCRUDNoAutoInc: TButton - Left = 20 - Top = 215 - Width = 303 - Height = 83 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 86 + Width = 121 + Height = 33 Caption = 'CRUD (no autoinc)' TabOrder = 10 OnClick = btnCRUDNoAutoIncClick end object btnCRUDWithStringPKs: TButton - Left = 20 - Top = 313 - Width = 303 - Height = 82 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 125 + Width = 121 + Height = 33 Caption = 'CRUD (string pks)' TabOrder = 11 OnClick = btnCRUDWithStringPKsClick end object btnWithSpaces: TButton - Left = 20 - Top = 410 - Width = 303 - Height = 83 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 164 + Width = 121 + Height = 33 Caption = 'CRUD (entity with spaces)' TabOrder = 12 WordWrap = True OnClick = btnWithSpacesClick end object btnCountWithRQL: TButton - Left = 360 - Top = 215 - Width = 303 - Height = 83 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 86 + Width = 121 + Height = 33 Caption = 'Count with RQL' TabOrder = 13 OnClick = btnCountWithRQLClick end object btnReadAndWriteOnly: TButton - Left = 360 - Top = 313 - Width = 303 - Height = 82 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 125 + Width = 121 + Height = 33 Caption = 'R/O, R/W' TabOrder = 14 OnClick = btnReadAndWriteOnlyClick end object btnClientGeneratedPK: TButton - Left = 360 - Top = 410 - Width = 303 - Height = 83 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 164 + Width = 121 + Height = 33 Caption = 'Client Generated PKs' TabOrder = 15 OnClick = btnClientGeneratedPKClick end object btnAttributes: TButton - Left = 360 - Top = 508 - Width = 303 - Height = 82 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 203 + Width = 121 + Height = 33 Caption = 'Attributes' TabOrder = 16 OnClick = btnAttributesClick end object btnJSON_XML_Types: TButton - Left = 360 - Top = 605 - Width = 303 - Height = 88 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 242 + Width = 121 + Height = 35 Caption = 'JSON && XML' TabOrder = 17 OnClick = btnJSON_XML_TypesClick end object btnMerge: TButton - Left = 360 - Top = 708 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 283 + Width = 121 + Height = 34 Caption = 'Merge' TabOrder = 18 OnClick = btnMergeClick end object btnTableFilter: TButton - Left = 360 - Top = 808 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 323 + Width = 121 + Height = 34 Caption = 'Table Filter' TabOrder = 19 OnClick = btnTableFilterClick end object btnPartitioning: TButton - Left = 360 - Top = 908 - Width = 303 - Height = 82 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 363 + Width = 121 + Height = 33 Caption = 'Table Partitioning' TabOrder = 20 OnClick = btnPartitioningClick end object btnCRUDWithGUID: TButton - Left = 20 - Top = 118 - Width = 303 - Height = 82 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 47 + Width = 121 + Height = 33 Caption = 'CRUD (with GUID PK)' TabOrder = 21 OnClick = btnCRUDWithGUIDClick end object btnOOP: TButton - Left = 360 - Top = 1005 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 402 + Width = 121 + Height = 34 Caption = 'OOP with Partitioning and Filtering' TabOrder = 22 WordWrap = True OnClick = btnOOPClick end object btnReadOnly: TButton - Left = 20 - Top = 1105 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 442 + Width = 121 + Height = 34 Caption = 'Read/Only Entities' TabOrder = 23 OnClick = btnReadOnlyClick end object btnSpeed: TButton - Left = 20 - Top = 1205 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 8 + Top = 482 + Width = 121 + Height = 34 Caption = 'Metadata Speed Test' TabOrder = 24 OnClick = btnSpeedClick end object btnRefresh: TButton - Left = 360 - Top = 1105 - Width = 303 - Height = 85 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 + Left = 144 + Top = 442 + Width = 121 + Height = 34 Caption = 'Manual Refresh' TabOrder = 25 OnClick = btnRefreshClick diff --git a/samples/activerecord_showcase/MainFormU.pas b/samples/activerecord_showcase/MainFormU.pas index 2dd5fdf2..f82b4dba 100644 --- a/samples/activerecord_showcase/MainFormU.pas +++ b/samples/activerecord_showcase/MainFormU.pas @@ -1040,6 +1040,7 @@ var lItem: TMVCActiveRecord; lCustomer: TCustomer; lCustList: TObjectList; + lRecCount: Integer; const cRQL1 = 'in(City,["Rome","London"]);sort(+code);limit(0,50)'; cRQL2 = 'and(eq(City,"Rome"),or(contains(CompanyName,"GAS"),contains(CompanyName,"Motors")))'; @@ -1133,6 +1134,114 @@ begin lList.Free; end; + + //****************************************************** + // Using "Load" methods ******************************** + //****************************************************** + Log('*************************************************'); + Log('** RQL Queries Test (using "Load" style methods)'); + Log('*************************************************'); + Log('>> RQL Query (1) - ' + cRQL1); + lList := TMVCActiveRecordList.Create; + try + TMVCActiveRecord.SelectRQL(TCustomer, cRQL1, 20, lList); + Log(lList.Count.ToString + ' record/s found'); + for lItem in lList do + begin + lCustomer := TCustomer(lItem); + Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault, lCustomer.City])); + end; + finally + lList.Free; + end; + + Log('>> RQL Query (2) - ' + cRQL2); + lCustList := TObjectList.Create; + try + lRecCount := TMVCActiveRecord.SelectRQL(cRQL2, 20, lCustList); + Log(lRecCount.ToString + ' record/s found'); + for lCustomer in lCustList do + begin + Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault, lCustomer.City])); + end; + finally + lCustList.Free; + end; + + Log('**RQL Query (3) - ' + cRQL2); + lList := TMVCActiveRecordList.Create; + try + lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, cRQL2, 20, lList); + Log(lRecCount.ToString + ' record/s found'); + for lItem in lList do + begin + lCustomer := TCustomer(lItem); + Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault, lCustomer.City])); + end; + finally + lList.Free; + end; + + Log('**RQL Query (4) - with limit 20'); + lList := TMVCActiveRecordList.Create; + try + lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, '', 20, lList); + Log(lRecCount.ToString + ' record/s found'); + Assert(lRecCount = 20); + Assert(lList.Count = lRecCount); + finally + lList.Free; + end; + + Log('**RQL Query (5) - sort by code with limit 20'); + lList := TMVCActiveRecordList.Create; + try + lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, 'sort(+code)', 20, lList); + Log(lRecCount.ToString + ' record/s found'); + Assert(lRecCount = lList.Count); + Assert(lList.Count = 20); + finally + lList.Free; + end; + + Log('**RQL Query (6) - with limit 10'); + lList := TMVCActiveRecordList.Create; + try + lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, '', 10, lList); + Log(lList.Count.ToString + ' record/s found'); + Assert(lRecCount = lList.Count); + Assert(lList.Count = 10); + finally + lList.Free; + end; + + Log('**RQL Query (7) - with limit 1'); + lList := TMVCActiveRecordList.Create; + try + lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, '', 1, lList); + Log(lList.Count.ToString + ' record/s found'); + Assert(lList.Count = 1); + Assert(lRecCount = lList.Count); + finally + lList.Free; + end; + + Log('**RQL Query (8) - with limit 0'); + lList := TMVCActiveRecordList.Create; + try + lRecCount := TMVCActiveRecord.SelectRQL(TCustomer, '', 0, lList); + Log(lList.Count.ToString + ' record/s found'); + Assert(lList.Count = 0); + Assert(lRecCount = lList.Count); + finally + lList.Free; + end; + + + end; procedure TMainForm.btnSelectClick(Sender: TObject); diff --git a/sources/MVCFramework.ActiveRecord.pas b/sources/MVCFramework.ActiveRecord.pas index 877b7a76..59e18fb6 100644 --- a/sources/MVCFramework.ActiveRecord.pas +++ b/sources/MVCFramework.ActiveRecord.pas @@ -333,7 +333,9 @@ type function InternalCount(const RQL: string): int64; function InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer) - : TMVCActiveRecordList; + : TMVCActiveRecordList; overload; + function InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer; + const OutList: TMVCActiveRecordList): UInt32; overload; public constructor Create(aLazyLoadConnection: Boolean); overload; { cannot be virtual! } @@ -392,18 +394,33 @@ type class function Select(const aClass: TMVCActiveRecordClass; const SQL: string; const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList; overload; + class function Select(const aClass: TMVCActiveRecordClass; const SQL: string; + const Params: array of Variant; + const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32; overload; class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; const MaxRecordCount: Integer) : TMVCActiveRecordList; overload; + class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; + const MaxRecordCount: Integer; const OutList: TMVCActiveRecordList): UInt32; overload; class function DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): int64; function SelectRQL(const RQL: string; const MaxRecordCount: Integer) : TMVCActiveRecordList; overload; - class function Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string; + class function Where( + const aClass: TMVCActiveRecordClass; + const SQLWhere: string; const Params: array of Variant) : TMVCActiveRecordList; overload; - class function Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string; + class function Where( + const aClass: TMVCActiveRecordClass; + const SQLWhere: string; const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList; overload; + class function Where( + const aClass: TMVCActiveRecordClass; + const SQLWhere: string; + const Params: array of Variant; + const Connection: TFDConnection; + const OutList: TMVCActiveRecordList): UInt32; overload; class function All(const aClass: TMVCActiveRecordClass): TObjectList; overload; class function DeleteAll(const aClass: TMVCActiveRecordClass): int64; overload; @@ -451,13 +468,27 @@ type const RaiseExceptionIfNotFound: Boolean = True): T; overload; class function GetByPK(const aValue: TGuid; const RaiseExceptionIfNotFound: Boolean = True): T; overload; + /// + /// Returns a TObjectList from a SQL using variant params + /// class function Select(const SQL: string; const Params: array of Variant; const Options: TMVCActiveRecordLoadOptions = []): TObjectList; overload; + /// + /// Returns a TObjectList from a SQL using typed params + /// class function Select(const SQL: string; const Params: array of Variant; const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions = []) : TObjectList; overload; + /// + /// Fills a TObjectList from a SQL using typed params. + /// Returns number of the records in the list (not only the selected records, but the current .Count of the list) + /// + class function Select(const SQL: string; const Params: array of Variant; + const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions; + const OutList: TObjectList): UInt32; overload; + class function SelectOne(const SQL: string; const Params: array of Variant; const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions = []; @@ -468,6 +499,8 @@ type class function SelectRQL(const RQL: string; const MaxRecordCount: Integer) : TObjectList; overload; + class function SelectRQL(const RQL: string; + const MaxRecordCount: Integer; const OutList: TObjectList): UInt32; overload; class function SelectOneByRQL(const RQL: string; const RaiseExceptionIfNotFound: Boolean = True): T; overload; class function All: TObjectList; overload; @@ -483,6 +516,10 @@ type class function Where(const SQLWhere: string; const Params: array of Variant; const ParamTypes: array of TFieldType): TObjectList; overload; + class function Where(const SQLWhere: string; + const Params: array of Variant; + const ParamTypes: array of TFieldType; + const OutList: TObjectList): UInt32; overload; class function GetOneByWhere(const SQLWhere: string; const Params: array of Variant; const RaiseExceptionIfNotFound: Boolean = True): T; overload; class function GetOneByWhere(const SQLWhere: string; @@ -1419,6 +1456,16 @@ begin Result := GetScalar(lSQL, []); end; +function TMVCActiveRecord.InternalSelectRQL(const RQL: string; + const MaxRecordCount: Integer; const OutList: TMVCActiveRecordList): UInt32; +var + lSQL: string; +begin + lSQL := SQLGenerator.CreateSQLWhereByRQL(RQL, GetMapping, True, false, MaxRecordCount); + LogD(Format('RQL [%s] => SQL [%s]', [RQL, lSQL])); + Result := Where(TMVCActiveRecordClass(Self.ClassType), lSQL, [], nil, OutList); +end; + function TMVCActiveRecord.InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer): TMVCActiveRecordList; var lSQL: string; @@ -1657,6 +1704,52 @@ begin end; end; +class function TMVCActiveRecordHelper.SelectRQL(const RQL: string; + const MaxRecordCount: Integer; const OutList: TObjectList): UInt32; +var + lAR: TMVCActiveRecord; + lSQL: string; +begin + lAR := T.Create; + try + lSQL := lAR.SQLGenerator.CreateSQLWhereByRQL(RQL, lAR.GetMapping, MaxRecordCount > -1, false, MaxRecordCount).Trim; + lSQL := TMVCSQLGenerator.RemoveInitialWhereKeyword(lSQL); + Result := Where(lSQL, [], [], OutList); + finally + lAR.Free; + end; +end; + +class function TMVCActiveRecordHelper.Where(const SQLWhere: string; + const Params: array of Variant; const ParamTypes: array of TFieldType; + const OutList: TObjectList): UInt32; +var + lAR: TMVCActiveRecord; + lFilter: string; +begin + lAR := T.Create; + try + lFilter := lAR.SQLGenerator.GetDefaultSQLFilter(True); + if SQLWhere.Trim.IsEmpty() or SQLWhere.Trim.StartsWith('/*limit*/') or SQLWhere.Trim.StartsWith('/*sort*/') then + begin + Result := Select(lAR.GenerateSelectSQL + lFilter + SQLWhere, Params, ParamTypes, [], OutList); + end + else + begin + if lFilter.IsEmpty then + begin + Result := Select(lAR.GenerateSelectSQL + ' WHERE ' + SQLWhere, Params, ParamTypes, [], OutList); + end + else + begin + Result := Select(lAR.GenerateSelectSQL + lFilter + ' AND ' + SQLWhere, Params, ParamTypes, [], OutList); + end; + end; + finally + lAR.Free; + end; +end; + function TMVCActiveRecord.GetPartitionInfo: TPartitionInfo; var lRQLCompilerClass: TRQLCompilerClass; @@ -2454,29 +2547,14 @@ end; class function TMVCActiveRecord.Select(const aClass: TMVCActiveRecordClass; const SQL: string; const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList; -var - lDataSet: TDataSet; - lAR: TMVCActiveRecord; begin Result := TMVCActiveRecordList.Create; try - lDataSet := ExecQuery(SQL, Params, Connection, True, False); - try - while not lDataSet.Eof do - begin - lAR := aClass.Create; - Result.Add(lAR); - lAR.LoadByDataset(lDataSet); - lDataSet.Next; - end; - finally - lDataSet.Free; - end; + Select(aClass, SQL, Params, Connection, Result); except Result.Free; raise; end; - end; class function TMVCActiveRecord.SelectDataSet(const SQL: string; const Params: array of Variant; @@ -2502,6 +2580,41 @@ begin Result := InternalSelectRQL(RQL, MaxRecordCount); end; +class function TMVCActiveRecord.SelectRQL(const aClass: TMVCActiveRecordClass; + const RQL: string; const MaxRecordCount: Integer; + const OutList: TMVCActiveRecordList): UInt32; +var + lAR: TMVCActiveRecord; +begin + lAR := aClass.Create(True); + try + Result := lAR.InternalSelectRQL(RQL, MaxRecordCount, OutList); + finally + lAR.Free; + end; +end; + +class function TMVCActiveRecordHelper.Select(const SQL: string; const Params: array of Variant; + const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions; const OutList: TObjectList): UInt32; +var + lDataSet: TDataSet; + lAR: TMVCActiveRecord; +begin + lDataSet := ExecQuery(SQL, Params, ParamTypes, True, False); + try + while not lDataSet.Eof do + begin + lAR := T.Create; + OutList.Add(lAR); + lAR.LoadByDataset(lDataSet, Options); + lDataSet.Next; + end; + Result := OutList.Count; + finally + lDataSet.Free; + end; +end; + class function TMVCActiveRecordHelper.Select(const SQL: string; const Params: array of Variant; const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions): TObjectList; var @@ -2511,18 +2624,7 @@ var begin Result := TObjectList.Create(True); try - lDataSet := ExecQuery(SQL, Params, ParamTypes, True, False); - try - while not lDataSet.Eof do - begin - lAR := T.Create; - Result.Add(lAR); - lAR.LoadByDataset(lDataSet, Options); - lDataSet.Next; - end; - finally - lDataSet.Free; - end; + Select(SQL, Params, ParamTypes, Options, Result); except Result.Free; raise; @@ -2581,28 +2683,13 @@ end; class function TMVCActiveRecordHelper.Where(const SQLWhere: string; const Params: array of Variant; const ParamTypes: array of TFieldType): TObjectList; -var - lAR: TMVCActiveRecord; - lFilter: string; begin - lAR := T.Create; + Result := TObjectList.Create(True); try - lFilter := lAR.SQLGenerator.GetDefaultSQLFilter(True); - if SQLWhere.Trim.IsEmpty() or SQLWhere.Trim.StartsWith('/*limit*/') or SQLWhere.Trim.StartsWith('/*sort*/') then - begin - Result := Select(lAR.GenerateSelectSQL + lFilter + SQLWhere, Params, ParamTypes) - end - else - begin - if lFilter.IsEmpty then - Result := Select(lAR.GenerateSelectSQL + ' WHERE ' + SQLWhere, Params, ParamTypes) - else - begin - Result := Select(lAR.GenerateSelectSQL + lFilter + ' AND ' + SQLWhere, Params, ParamTypes); - end; - end; - finally - lAR.Free; + Where(SQLWhere, Params, ParamTypes, Result); + except + Result.Free; + raise; end; end; @@ -3000,6 +3087,20 @@ begin OnAfterInsertOrUpdate; end; +class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; + const SQLWhere: string; const Params: array of Variant; + const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32; +var + lAR: TMVCActiveRecord; +begin + lAR := aClass.Create; + try + Result := Select(aClass, lAR.GenerateSelectSQL + SQLWhere, Params, Connection, OutList); + finally + lAR.Free; + end; +end; + procedure TMVCActiveRecord.AddChildren(const ChildObject: TObject); begin if fChildren = nil then @@ -3051,14 +3152,13 @@ end; class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string; const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList; -var - lAR: TMVCActiveRecord; begin - lAR := aClass.Create; + Result := TMVCActiveRecordList.Create; try - Result := Select(aClass, lAR.GenerateSelectSQL + SQLWhere, Params, Connection); - finally - lAR.Free; + Where(aClass, SQLWhere, Params, Connection, Result); + except + Result.Free; + raise; end; end; @@ -4063,6 +4163,28 @@ begin inherited; end; +class function TMVCActiveRecord.Select(const aClass: TMVCActiveRecordClass; + const SQL: string; const Params: array of Variant; + const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32; +var + lDataSet: TDataSet; + lAR: TMVCActiveRecord; +begin + lDataSet := ExecQuery(SQL, Params, Connection, True, False); + try + while not lDataSet.Eof do + begin + lAR := aClass.Create; + OutList.Add(lAR); + lAR.LoadByDataset(lDataSet); + lDataSet.Next; + end; + Result := OutList.Count; + finally + lDataSet.Free; + end; +end; + initialization gConnectionsLock := TObject.Create; From 0053885bc1eda09f61280c860df4fc80a968348b Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Tue, 8 Aug 2023 18:54:44 +0200 Subject: [PATCH 20/31] Better exception description and better recognize of boolean type when database doesn't know boolean field types --- sources/MVCFramework.ActiveRecord.pas | 4 ++-- sources/MVCFramework.Serializer.Commons.pas | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sources/MVCFramework.ActiveRecord.pas b/sources/MVCFramework.ActiveRecord.pas index 59e18fb6..83aa66c8 100644 --- a/sources/MVCFramework.ActiveRecord.pas +++ b/sources/MVCFramework.ActiveRecord.pas @@ -1330,7 +1330,7 @@ begin begin if [eaCreate, eaUpdate, eaDelete] * lTableMap.fEntityAllowedActions <> [] then begin - raise Exception.Create('Cannot find TableNameAttribute'); + raise Exception.Create('Cannot find TableNameAttribute on class ' + ClassName + ' - [HINT] Is this class decorated with MVCTable and its fields with MVCTableField?'); end; end; @@ -1390,7 +1390,7 @@ begin lTableMap.fMap.EndUpdates; if (lPKCount + lTableMap.fMap.WritableFieldsCount + lTableMap.fMap.ReadableFieldsCount) = 0 then raise EMVCActiveRecord.Create( - 'No fields nor PKs defined. [HINT] Use MVCTableField in private fields'); + 'No fields nor PKs defined in class ' + ClassName + '. [HINT] Use MVCTableField in private fields'); lTableMap.fPartitionInfoInternal := nil; ActiveRecordTableMapRegistry.AddTableMap(Self, lTableMap); diff --git a/sources/MVCFramework.Serializer.Commons.pas b/sources/MVCFramework.Serializer.Commons.pas index 4dd392f0..d1095fe3 100644 --- a/sources/MVCFramework.Serializer.Commons.pas +++ b/sources/MVCFramework.Serializer.Commons.pas @@ -1141,7 +1141,7 @@ begin begin // sqlite doesn't support boolean, so are identified as integers // so we need to do some more checks... - if (aRTTIField.FieldType.TypeKind = tkEnumeration) and (aRTTIField.Name.ToLower.Contains('bool')) then + if (aRTTIField.FieldType.TypeKind = tkEnumeration) and (aRTTIField.FieldType.Handle = TypeInfo(Boolean)) then begin aRTTIField.SetValue(AObject, AField.AsInteger = 1); end From 47c3003f15c6e10e13986d53d19c9981faf5eafb Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Wed, 9 Aug 2023 00:46:31 +0200 Subject: [PATCH 21/31] Better organization of method between TMVCActiveRecord and TMVCActiveRecordHelper --- sources/MVCFramework.ActiveRecord.pas | 192 +++++++++++++++----------- 1 file changed, 110 insertions(+), 82 deletions(-) diff --git a/sources/MVCFramework.ActiveRecord.pas b/sources/MVCFramework.ActiveRecord.pas index 83aa66c8..342bf2f1 100644 --- a/sources/MVCFramework.ActiveRecord.pas +++ b/sources/MVCFramework.ActiveRecord.pas @@ -256,7 +256,7 @@ type const Unidirectional: Boolean; const DirectExecute: Boolean): TDataSet; overload; procedure FillPrimaryKey(const SequenceName: string); - function ExecNonQuery(const SQL: string; RefreshAutoGenerated: Boolean = false): int64; + function ExecNonQuery(const SQL: string; RefreshAutoGenerated: Boolean = false): Int64; overload; class function GetByPK(aActiveRecord: TMVCActiveRecord; const aValue: string; const aFieldType: TFieldType; const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord; overload; @@ -330,8 +330,7 @@ type function GenerateSelectSQL: string; function SQLGenerator: TMVCSQLGenerator; - - function InternalCount(const RQL: string): int64; + function InternalCount(const RQL: string): Int64; function InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer) : TMVCActiveRecordList; overload; function InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer; @@ -356,7 +355,7 @@ type const aRaiseException: Boolean = True): Boolean; procedure Insert; function GetMapping: TMVCFieldsMapping; - function LoadByPK(const id: int64): Boolean; overload; virtual; + function LoadByPK(const id: Int64): Boolean; overload; virtual; function LoadByPK(const id: string): Boolean; overload; virtual; function LoadByPK(const id: TGuid): Boolean; overload; virtual; function LoadByPK(const id: string; const aFieldType: TFieldType): Boolean; overload; virtual; @@ -374,66 +373,22 @@ type procedure AddChildren(const ChildObject: TObject); procedure RemoveChildren(const ChildObject: TObject); function GetPrimaryKeyFieldType: TFieldType; - // dynamic access - property Attributes[const AttrName: string]: TValue read GetAttributes write SetAttributes; + + property Attributes[const AttrName: string]: TValue + read GetAttributes + write SetAttributes; + [MVCDoNotSerialize] - property TableName: string read GetTableName write SetTableName; + property TableName: string + read GetTableName + write SetTableName; + [MVCDoNotSerialize] - property PrimaryKeyIsAutogenerated: Boolean read GetPrimaryKeyIsAutogenerated + property PrimaryKeyIsAutogenerated: Boolean + read GetPrimaryKeyIsAutogenerated write SetPrimaryKeyIsAutogenerated; - class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: int64; - const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload; - class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string; - const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload; - class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: TGuid; - const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload; + class function GetScalar(const SQL: string; const Params: array of Variant): Variant; - class function Select(const aClass: TMVCActiveRecordClass; const SQL: string; - const Params: array of Variant) - : TMVCActiveRecordList; overload; - class function Select(const aClass: TMVCActiveRecordClass; const SQL: string; - const Params: array of Variant; - const Connection: TFDConnection): TMVCActiveRecordList; overload; - class function Select(const aClass: TMVCActiveRecordClass; const SQL: string; - const Params: array of Variant; - const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32; overload; - class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; - const MaxRecordCount: Integer) - : TMVCActiveRecordList; overload; - class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; - const MaxRecordCount: Integer; const OutList: TMVCActiveRecordList): UInt32; overload; - class function DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): int64; - function SelectRQL(const RQL: string; const MaxRecordCount: Integer) - : TMVCActiveRecordList; overload; - class function Where( - const aClass: TMVCActiveRecordClass; - const SQLWhere: string; - const Params: array of Variant) - : TMVCActiveRecordList; overload; - class function Where( - const aClass: TMVCActiveRecordClass; - const SQLWhere: string; - const Params: array of Variant; - const Connection: TFDConnection): TMVCActiveRecordList; overload; - class function Where( - const aClass: TMVCActiveRecordClass; - const SQLWhere: string; - const Params: array of Variant; - const Connection: TFDConnection; - const OutList: TMVCActiveRecordList): UInt32; overload; - class function All(const aClass: TMVCActiveRecordClass): TObjectList; - overload; - class function DeleteAll(const aClass: TMVCActiveRecordClass): int64; overload; - function Count(const RQL: string = ''): int64; overload; - class function Count(const aClass: TMVCActiveRecordClass; const RQL: string = '') - : int64; overload; - class function SelectDataSet(const SQL: string; const Params: array of Variant; - const Unidirectional: Boolean = False; - const DirectExecute: Boolean = False): TDataSet; overload; - class function SelectDataSet(const SQL: string; const Params: array of Variant; - const ParamTypes: array of TFieldType; - const Unidirectional: Boolean = False; - const DirectExecute: Boolean = False): TDataSet; overload; class function CurrentConnection: TFDConnection; end; @@ -460,14 +415,23 @@ type end; TMVCActiveRecordHelper = class helper for TMVCActiveRecord + { GetByPK } + class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: Int64; + const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload; + class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string; + const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload; + class function GetByPK(const aClass: TMVCActiveRecordClass; const aValue: TGuid; + const RaiseExceptionIfNotFound: Boolean = True): TMVCActiveRecord; overload; class function GetByPK(const aValue: string; const aFieldType: TFieldType; const RaiseExceptionIfNotFound: Boolean): T; overload; - class function GetByPK(const aValue: int64; + class function GetByPK(const aValue: Int64; const RaiseExceptionIfNotFound: Boolean = True): T; overload; class function GetByPK(const aValue: string; const RaiseExceptionIfNotFound: Boolean = True): T; overload; class function GetByPK(const aValue: TGuid; const RaiseExceptionIfNotFound: Boolean = True): T; overload; + + { Select } /// /// Returns a TObjectList from a SQL using variant params /// @@ -489,6 +453,17 @@ type const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions; const OutList: TObjectList): UInt32; overload; + class function Select(const aClass: TMVCActiveRecordClass; const SQL: string; + const Params: array of Variant) + : TMVCActiveRecordList; overload; + class function Select(const aClass: TMVCActiveRecordClass; const SQL: string; + const Params: array of Variant; + const Connection: TFDConnection): TMVCActiveRecordList; overload; + class function Select(const aClass: TMVCActiveRecordClass; const SQL: string; + const Params: array of Variant; + const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32; overload; + + { SelectOne } class function SelectOne(const SQL: string; const Params: array of Variant; const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions = []; @@ -496,6 +471,11 @@ type class function SelectOne(const SQL: string; const Params: array of Variant; const RaiseExceptionIfNotFound: Boolean = True): T; overload; + + + { SelectRQL } + function SelectRQL(const RQL: string; const MaxRecordCount: Integer) + : TMVCActiveRecordList; overload; class function SelectRQL(const RQL: string; const MaxRecordCount: Integer) : TObjectList; overload; @@ -503,9 +483,18 @@ type const MaxRecordCount: Integer; const OutList: TObjectList): UInt32; overload; class function SelectOneByRQL(const RQL: string; const RaiseExceptionIfNotFound: Boolean = True): T; overload; + class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; + const MaxRecordCount: Integer) + : TMVCActiveRecordList; overload; + class function SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; + const MaxRecordCount: Integer; const OutList: TMVCActiveRecordList): UInt32; overload; + + { Misc } class function All: TObjectList; overload; - class function DeleteRQL(const RQL: string = ''): int64; overload; - class function Count(const RQL: string = ''): int64; overload; + class function DeleteRQL(const RQL: string = ''): Int64; overload; + class function Count(const RQL: string = ''): Int64; overload; + + { Where } class function Where(const SQLWhere: string; const Params: array of Variant) : TObjectList; overload; @@ -520,6 +509,24 @@ type const Params: array of Variant; const ParamTypes: array of TFieldType; const OutList: TObjectList): UInt32; overload; + class function Where( + const aClass: TMVCActiveRecordClass; + const SQLWhere: string; + const Params: array of Variant) + : TMVCActiveRecordList; overload; + class function Where( + const aClass: TMVCActiveRecordClass; + const SQLWhere: string; + const Params: array of Variant; + const Connection: TFDConnection): TMVCActiveRecordList; overload; + class function Where( + const aClass: TMVCActiveRecordClass; + const SQLWhere: string; + const Params: array of Variant; + const Connection: TFDConnection; + const OutList: TMVCActiveRecordList): UInt32; overload; + + { GetXXXByWhere } class function GetOneByWhere(const SQLWhere: string; const Params: array of Variant; const RaiseExceptionIfNotFound: Boolean = True): T; overload; class function GetOneByWhere(const SQLWhere: string; @@ -530,8 +537,29 @@ type class function GetFirstByWhere(const SQLWhere: string; const Params: array of Variant; const ParamTypes: array of TFieldType; const RaiseExceptionIfNotFound: Boolean = True): T; overload; + + { Merge } class function Merge(CurrentList, NewList: TObjectList; const MergeMode: TMergeMode = [mmInsert, mmUpdate, mmDelete]): IMVCMultiExecutor; + + { Misc } + class function All(const aClass: TMVCActiveRecordClass): TObjectList; + overload; + class function DeleteAll(const aClass: TMVCActiveRecordClass): Int64; overload; + class function DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): Int64; overload; + function Count(const RQL: string = ''): Int64; overload; + class function Count(const aClass: TMVCActiveRecordClass; const RQL: string = '') + : int64; overload; + + { SelectDataSet } + class function SelectDataSet(const SQL: string; const Params: array of Variant; + const Unidirectional: Boolean = False; + const DirectExecute: Boolean = False): TDataSet; overload; + class function SelectDataSet(const SQL: string; const Params: array of Variant; + const ParamTypes: array of TFieldType; + const Unidirectional: Boolean = False; + const DirectExecute: Boolean = False): TDataSet; overload; + end; IMVCEntitiesRegistry = interface @@ -1541,19 +1569,19 @@ begin end; end; -class function TMVCActiveRecord.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string; +class function TMVCActiveRecordHelper.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string; const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord; begin Result := GetByPK(aClass.Create, aValue, ftString, RaiseExceptionIfNotFound); end; -class function TMVCActiveRecord.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: int64; +class function TMVCActiveRecordHelper.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: int64; const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord; begin Result := GetByPK(aClass.Create, aValue.ToString, ftInteger, RaiseExceptionIfNotFound); end; -class function TMVCActiveRecord.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: TGuid; +class function TMVCActiveRecordHelper.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: TGuid; const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord; begin Result := GetByPK(aClass.Create, aValue.ToString, ftGuid, RaiseExceptionIfNotFound); @@ -1826,7 +1854,7 @@ begin [GetEnumName(TypeInfo(TMVCEntityAction), Ord(aEntityAction)), ClassName]) at ReturnAddress; end; -class function TMVCActiveRecord.Count(const aClass: TMVCActiveRecordClass; const RQL: string): int64; +class function TMVCActiveRecordHelper.Count(const aClass: TMVCActiveRecordClass; const RQL: string): int64; var lAR: TMVCActiveRecord; begin @@ -1840,7 +1868,7 @@ begin end; end; -function TMVCActiveRecord.Count(const RQL: string = ''): int64; +function TMVCActiveRecordHelper.Count(const RQL: string = ''): int64; begin Result := InternalCount(RQL); end; @@ -1895,7 +1923,7 @@ begin OnAfterDelete; end; -class function TMVCActiveRecord.DeleteAll(const aClass: TMVCActiveRecordClass): int64; +class function TMVCActiveRecordHelper.DeleteAll(const aClass: TMVCActiveRecordClass): int64; var lAR: TMVCActiveRecord; begin @@ -1908,7 +1936,7 @@ begin end; end; -class function TMVCActiveRecord.DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): int64; +class function TMVCActiveRecordHelper.DeleteRQL(const aClass: TMVCActiveRecordClass; const RQL: string): int64; var lAR: TMVCActiveRecord; begin @@ -2539,13 +2567,13 @@ begin end; end; -class function TMVCActiveRecord.Select(const aClass: TMVCActiveRecordClass; const SQL: string; +class function TMVCActiveRecordHelper.Select(const aClass: TMVCActiveRecordClass; const SQL: string; const Params: array of Variant): TMVCActiveRecordList; begin Result := Select(aClass, SQL, Params, nil); end; -class function TMVCActiveRecord.Select(const aClass: TMVCActiveRecordClass; const SQL: string; +class function TMVCActiveRecordHelper.Select(const aClass: TMVCActiveRecordClass; const SQL: string; const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList; begin Result := TMVCActiveRecordList.Create; @@ -2557,7 +2585,7 @@ begin end; end; -class function TMVCActiveRecord.SelectDataSet(const SQL: string; const Params: array of Variant; +class function TMVCActiveRecordHelper.SelectDataSet(const SQL: string; const Params: array of Variant; const ParamTypes: array of TFieldType; const Unidirectional: Boolean; const DirectExecute: Boolean): TDataSet; begin Result := TMVCActiveRecord.ExecQuery(SQL, Params, ParamTypes, Unidirectional, DirectExecute); @@ -2569,18 +2597,18 @@ begin Result := Select(SQL, Params, [], Options); end; -class function TMVCActiveRecord.SelectDataSet(const SQL: string; const Params: array of Variant; +class function TMVCActiveRecordHelper.SelectDataSet(const SQL: string; const Params: array of Variant; const Unidirectional: Boolean; const DirectExecute: Boolean): TDataSet; begin Result := TMVCActiveRecord.ExecQuery(SQL, Params, Unidirectional, DirectExecute); end; -function TMVCActiveRecord.SelectRQL(const RQL: string; const MaxRecordCount: Integer): TMVCActiveRecordList; +function TMVCActiveRecordHelper.SelectRQL(const RQL: string; const MaxRecordCount: Integer): TMVCActiveRecordList; begin Result := InternalSelectRQL(RQL, MaxRecordCount); end; -class function TMVCActiveRecord.SelectRQL(const aClass: TMVCActiveRecordClass; +class function TMVCActiveRecordHelper.SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; const MaxRecordCount: Integer; const OutList: TMVCActiveRecordList): UInt32; var @@ -2693,7 +2721,7 @@ begin end; end; -class function TMVCActiveRecord.SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; +class function TMVCActiveRecordHelper.SelectRQL(const aClass: TMVCActiveRecordClass; const RQL: string; const MaxRecordCount: Integer): TMVCActiveRecordList; var lAR: TMVCActiveRecord; @@ -3087,7 +3115,7 @@ begin OnAfterInsertOrUpdate; end; -class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; +class function TMVCActiveRecordHelper.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string; const Params: array of Variant; const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32; var @@ -3113,7 +3141,7 @@ begin end; end; -class function TMVCActiveRecord.All(const aClass: TMVCActiveRecordClass): TObjectList; +class function TMVCActiveRecordHelper.All(const aClass: TMVCActiveRecordClass): TObjectList; var lAR: TMVCActiveRecord; begin @@ -3144,13 +3172,13 @@ begin end; end; -class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string; +class function TMVCActiveRecordHelper.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string; const Params: array of Variant): TMVCActiveRecordList; begin Result := Where(aClass, SQLWhere, Params, nil); end; -class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string; +class function TMVCActiveRecordHelper.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string; const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList; begin Result := TMVCActiveRecordList.Create; @@ -4163,7 +4191,7 @@ begin inherited; end; -class function TMVCActiveRecord.Select(const aClass: TMVCActiveRecordClass; +class function TMVCActiveRecordHelper.Select(const aClass: TMVCActiveRecordClass; const SQL: string; const Params: array of Variant; const Connection: TFDConnection; const OutList: TMVCActiveRecordList): UInt32; var From 636341d8227e6f6ccf918f4f0ce0669653f652bd Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Wed, 9 Aug 2023 01:23:24 +0200 Subject: [PATCH 22/31] NamedSQLQuery (WIP) --- samples/activerecord_showcase/EntitiesU.pas | 2 + samples/activerecord_showcase/MainFormU.dfm | 9 +++ samples/activerecord_showcase/MainFormU.pas | 31 +++++++++ sources/MVCFramework.ActiveRecord.pas | 76 +++++++++++++++++++++ 4 files changed, 118 insertions(+) diff --git a/samples/activerecord_showcase/EntitiesU.pas b/samples/activerecord_showcase/EntitiesU.pas index 59c8bdd2..075e99d2 100644 --- a/samples/activerecord_showcase/EntitiesU.pas +++ b/samples/activerecord_showcase/EntitiesU.pas @@ -105,6 +105,8 @@ type [MVCNameCase(ncLowerCase)] [MVCTable('customers')] + [MVCNamedSQLQuery('RatingLessThanPar', 'select * from customers where rating < ? order by code, city desc')] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select * from customers where rating = ? order by code, city desc')] TCustomer = class(TCustomEntity) private {$IFNDEF USE_SEQUENCES} diff --git a/samples/activerecord_showcase/MainFormU.dfm b/samples/activerecord_showcase/MainFormU.dfm index 5d1aeb54..c9e1704d 100644 --- a/samples/activerecord_showcase/MainFormU.dfm +++ b/samples/activerecord_showcase/MainFormU.dfm @@ -267,6 +267,15 @@ object MainForm: TMainForm TabOrder = 25 OnClick = btnRefreshClick end + object btnNamedQuery: TButton + Left = 144 + Top = 482 + Width = 121 + Height = 34 + Caption = 'Named Query' + TabOrder = 26 + OnClick = btnNamedQueryClick + end object FDConnection1: TFDConnection Left = 312 Top = 40 diff --git a/samples/activerecord_showcase/MainFormU.pas b/samples/activerecord_showcase/MainFormU.pas index f82b4dba..08a1b6b1 100644 --- a/samples/activerecord_showcase/MainFormU.pas +++ b/samples/activerecord_showcase/MainFormU.pas @@ -58,6 +58,7 @@ type btnReadOnly: TButton; btnSpeed: TButton; btnRefresh: TButton; + btnNamedQuery: TButton; procedure btnCRUDClick(Sender: TObject); procedure btnInheritanceClick(Sender: TObject); procedure btnMultiThreadingClick(Sender: TObject); @@ -86,6 +87,7 @@ type procedure btnReadOnlyClick(Sender: TObject); procedure btnSpeedClick(Sender: TObject); procedure btnRefreshClick(Sender: TObject); + procedure btnNamedQueryClick(Sender: TObject); private procedure Log(const Value: string); procedure LoadCustomers; @@ -649,6 +651,35 @@ begin 'in(City,["Rome","New York","London","Melbourne","Berlin"])').ToString + ' records'); end; +procedure TMainForm.btnNamedQueryClick(Sender: TObject); +begin + Log('** Named SQL Query'); + Log('Query: RatingLessThanPar'); + var lCustomers := TMVCActiveRecord.SelectByNamedQuery('RatingLessThanPar', [4], [ftInteger]); + try + for var lCustomer in lCustomers do + begin + Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault])); + end; + finally + lCustomers.Free; + end; + + Log('Query: RatingEqualsToPar'); + lCustomers := TMVCActiveRecord.SelectByNamedQuery('RatingEqualsToPar', [1], [ftInteger]); + try + for var lCustomer in lCustomers do + begin + Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault])); + end; + finally + lCustomers.Free; + end; + +end; + procedure TMainForm.btnNullablesClick(Sender: TObject); var lCustomer: TCustomer; diff --git a/sources/MVCFramework.ActiveRecord.pas b/sources/MVCFramework.ActiveRecord.pas index 342bf2f1..b91797c5 100644 --- a/sources/MVCFramework.ActiveRecord.pas +++ b/sources/MVCFramework.ActiveRecord.pas @@ -103,6 +103,11 @@ type procedure EndUpdates; end; + TQueryWithName = record + Name: String; + QueryText: String; + end; + TFieldsMap = class(TObjectDictionary) private fWritableFieldsCount: Integer; @@ -133,6 +138,13 @@ type constructor Create(const PartitionClause: String); end; + MVCNamedSQLQueryAttribute = class(MVCActiveRecordCustomAttribute) + public + Name: string; + SQLQuery: String; + constructor Create(aName: string; aSQLSelect: String); + end; + MVCTableFieldAttribute = class(MVCActiveRecordCustomAttribute) public FieldName: string; @@ -202,6 +214,7 @@ type fPrimaryKeyOptions: TMVCActiveRecordFieldOptions; fPrimaryKeySequenceName: string; fPrimaryKeyFieldType: TFieldType; + fNamedSQLQueries: TArray; public constructor Create; destructor Destroy; override; @@ -374,6 +387,8 @@ type procedure RemoveChildren(const ChildObject: TObject); function GetPrimaryKeyFieldType: TFieldType; + function FindSQLQueryByName(const QueryName: String; out NamedSQLQuery: TQueryWithName): Boolean; + property Attributes[const AttrName: string]: TValue read GetAttributes write SetAttributes; @@ -560,6 +575,12 @@ type const Unidirectional: Boolean = False; const DirectExecute: Boolean = False): TDataSet; overload; + { NamedQuery} + class function SelectByNamedQuery( + const QueryName: String; + const Params: array of Variant; + const ParamTypes: array of TFieldType; + const Options: TMVCActiveRecordLoadOptions = []): TObjectList; end; IMVCEntitiesRegistry = interface @@ -1299,6 +1320,22 @@ begin end; end; +function TMVCActiveRecord.FindSQLQueryByName(const QueryName: String; + out NamedSQLQuery: TQueryWithName): Boolean; +var + I: Integer; +begin + for I := Low(fTableMap.fNamedSQLQueries) to High(fTableMap.fNamedSQLQueries) do + begin + if SameText(QueryName, fTableMap.fNamedSQLQueries[I].Name) then + begin + NamedSQLQuery := fTableMap.fNamedSQLQueries[I]; + Exit(True); + end; + end; + Result := False; +end; + class function TMVCActiveRecord.ExecQuery(const SQL: string; const Values: array of Variant; const Unidirectional: Boolean; const DirectExecute: Boolean): TDataSet; begin @@ -1313,6 +1350,7 @@ var lPrimaryFieldTypeAsStr: string; lTableMap: TMVCTableMap; lPKCount: Integer; + lNamedSQLQueryCount: Integer; begin if ActiveRecordTableMapRegistry.TryGetValue(Self, fTableMap) then begin @@ -1334,6 +1372,7 @@ begin lTableMap.fRTTIType := gCtx.GetType(Self.ClassInfo) as TRttiInstanceType; lTableMap.fObjAttributes := lTableMap.fRTTIType.GetAttributes; lPKCount := 0; + lNamedSQLQueryCount := Length(lTableMap.fNamedSQLQueries); for lAttribute in lTableMap.fObjAttributes do begin if lAttribute is MVCTableAttribute then @@ -1352,6 +1391,14 @@ begin lTableMap.fPartitionClause := MVCPartitionAttribute(lAttribute).PartitionClause; Continue; end; + if lAttribute is MVCNamedSQLQueryAttribute then + begin + Inc(lNamedSQLQueryCount); + SetLength(lTableMap.fNamedSQLQueries, lNamedSQLQueryCount); + lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].Name := MVCNamedSQLQueryAttribute(lAttribute).Name; + lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].QueryText := MVCNamedSQLQueryAttribute(lAttribute).SQLQuery; + Continue; + end; end; if lTableMap.fTableName = '' then @@ -2643,6 +2690,26 @@ begin end; end; +class function TMVCActiveRecordHelper.SelectByNamedQuery( + const QueryName: String; const Params: array of Variant; + const ParamTypes: array of TFieldType; + const Options: TMVCActiveRecordLoadOptions): TObjectList; +var + lT: T; + lSQLQuery: TQueryWithName; +begin + lT := T.Create; + try + if not lT.FindSQLQueryByName(QueryName, lSQLQuery) then + begin + raise EMVCActiveRecord.CreateFmt('NamedSQLQuery not found: %s', [QueryName]); + end; + Result := Select(lSQLQuery.QueryText, Params, ParamTypes, Options); + finally + lT.Free; + end; +end; + class function TMVCActiveRecordHelper.Select(const SQL: string; const Params: array of Variant; const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions): TObjectList; var @@ -4213,6 +4280,15 @@ begin end; end; +{ MVCNamedSQLQueryAttribute } + +constructor MVCNamedSQLQueryAttribute.Create(aName, aSQLSelect: String); +begin + inherited Create; + Name := aName; + SQLQuery := aSQLSelect; +end; + initialization gConnectionsLock := TObject.Create; From b59f8f6421e298a59c7b864e33483600b1a872f9 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Wed, 9 Aug 2023 10:55:34 +0200 Subject: [PATCH 23/31] Added MVCNamedSQLQuery and MVCNamedRQLQuery (Named queries support is complete) --- README.md | 152 +++++++++++++++++ samples/activerecord_showcase/EntitiesU.pas | 35 +++- samples/activerecord_showcase/MainFormU.dfm | 9 + samples/activerecord_showcase/MainFormU.pas | 52 +++++- sources/MVCFramework.ActiveRecord.pas | 160 ++++++++++++++++-- .../general/Several/ActiveRecordTestsU.pas | 70 ++++++++ unittests/general/Several/BOs.pas | 22 +++ 7 files changed, 483 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index e8e83105..767b59e8 100644 --- a/README.md +++ b/README.md @@ -468,6 +468,158 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma - Removed `statuscode` and `reasonstring` from exception's JSON rendering. +- ⚡ New! NamedQueries support for TMVCActiveRecord. + + - `MVCNamedSQLQuery` allows to define a "named query" which is, well, a SQL query with a name. Then such query can be used by the method `SelectByNamedQuery`. MOreover in the attribute it is possible to define on which backend engine that query is usable. In this way you can define optimized query for each supported DMBS you need. Check the example below. + + ```delphi + type + [MVCTable('customers')] + [MVCNamedSQLQuery('RatingLessThanPar', 'select * from customers where rating < ? order by code, city desc')] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*firebird*/ * from customers where rating = ? order by code, city desc', + TMVCActiveRecordBackEnd.FirebirdSQL)] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*postgres*/ * from customers where rating = ? order by code, city desc', + TMVCActiveRecordBackEnd.PostgreSQL)] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*all*/ * from customers where rating = ? order by code, city desc')] + TCustomer = class(TCustomEntity) + private + // usual field declaration + end; + + //** then in the code + + Log('** Named SQL Query'); + Log('QuerySQL: RatingLessThanPar'); + var lCustomers := TMVCActiveRecord.SelectByNamedQuery('RatingLessThanPar', [4], [ftInteger]); + try + for var lCustomer in lCustomers do + begin + Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault])); + end; + finally + lCustomers.Free; + end; + + Log('QuerySQL: RatingEqualsToPar'); + lCustomers := TMVCActiveRecord.SelectByNamedQuery('RatingEqualsToPar', [3], [ftInteger]); + try + for var lCustomer in lCustomers do + begin + Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault])); + end; + finally + lCustomers.Free; + end; + + ``` + + The same approach is available for RQL query, which can be used also for Count and Delete operations but doesnt allows to specify the backend (because RQL has an actual compiler to adapt the generated SQL to each RDBMS) + + ```delphi + type + [MVCTable('customers')] + [MVCNamedSQLQuery('RatingLessThanPar', 'select * from customers where rating < ? order by code, city desc')] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*firebird*/ * from customers where rating = ? order by code, city desc', + TMVCActiveRecordBackEnd.FirebirdSQL)] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*postgres*/ * from customers where rating = ? order by code, city desc', + TMVCActiveRecordBackEnd.PostgreSQL)] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*all*/ * from customers where rating = ? order by code, city desc')] + [MVCNamedRQLQuery('RatingLessThanPar', 'lt(rating,%d);sort(+code,-city)')] + [MVCNamedRQLQuery('RatingEqualsToPar', 'eq(rating,%d);sort(+code,-city)')] + TCustomer = class(TCustomEntity) + private + // usual field declaration + end; + + //** then in the code + + Log('** Named RQL Query'); + Log('QueryRQL: RatingLessThanPar'); + lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery('RatingLessThanPar', [4], 1000); + try + for var lCustomer in lCustomers do + begin + Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault])); + end; + finally + lCustomers.Free; + end; + + Log('QueryRQL: RatingEqualsToPar'); + lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery('RatingEqualsToPar', [3], 1000); + try + for var lCustomer in lCustomers do + begin + Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault])); + end; + finally + lCustomers.Free; + end; + + ``` + + Now, having SQL and RQL named queries, it is possibile to have an entity which is not mapped on a specific table but loaded only by named queries. + + ```delphi + type + [MVCEntityActions([eaRetrieve])] + [MVCNamedSQLQuery('CustomersInTheSameCity', + 'SELECT c.id, c.DESCRIPTION, c.city, c.code, c.rating, (SELECT count(*) - 1 FROM customers c2 WHERE c2.CITY = c.CITY) customers_in_the_same_city ' + + 'FROM CUSTOMERS c WHERE city IS NOT NULL AND city <> '''' ORDER BY customers_in_the_same_city')] + TCustomerStats = class(TCustomEntity) {not mapped on an actual table or view} + private + [MVCTableField('id', [foPrimaryKey, foAutoGenerated])] + fID: NullableInt64; + [MVCTableField('code')] + fCode: NullableString; + [MVCTableField('description')] + fCompanyName: NullableString; + [MVCTableField('city')] + fCity: string; + [MVCTableField('rating')] + fRating: NullableInt32; + [MVCTableField('customers_in_the_same_city')] + fCustomersInTheSameCity: Int32; + public + property ID: NullableInt64 read fID write fID; + property Code: NullableString read fCode write fCode; + property CompanyName: NullableString read fCompanyName write fCompanyName; + property City: string read fCity write fCity; + property Rating: NullableInt32 read fRating write fRating; + property CustomersInTheSameCity: Int32 read fCustomersInTheSameCity write fCustomersInTheSameCity; + end; + + + //** then in the code + + procedure TMainForm.btnVirtualEntitiesClick(Sender: TObject); + begin + var lCustStats := TMVCActiveRecord.SelectByNamedQuery('CustomersInTheSameCity', [], []); + try + for var lCustomer in lCustStats do + begin + Log(Format('%4d - %8.5s - %s - (%d other customers in the same city)', [ + lCustomer.ID.ValueOrDefault, + lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault, + lCustomer.CustomersInTheSameCity + ])); + end; + finally + lCustStats.Free; + end; + end; + + + ``` + + + + ## Old Versions ### What's New in dmvcframework-3.2.3-radium diff --git a/samples/activerecord_showcase/EntitiesU.pas b/samples/activerecord_showcase/EntitiesU.pas index 075e99d2..7750bd1d 100644 --- a/samples/activerecord_showcase/EntitiesU.pas +++ b/samples/activerecord_showcase/EntitiesU.pas @@ -106,7 +106,11 @@ type [MVCNameCase(ncLowerCase)] [MVCTable('customers')] [MVCNamedSQLQuery('RatingLessThanPar', 'select * from customers where rating < ? order by code, city desc')] - [MVCNamedSQLQuery('RatingEqualsToPar', 'select * from customers where rating = ? order by code, city desc')] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*firebird*/ * from customers where rating = ? order by code, city desc', TMVCActiveRecordBackEnd.FirebirdSQL)] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*postgres*/ * from customers where rating = ? order by code, city desc', TMVCActiveRecordBackEnd.PostgreSQL)] + [MVCNamedSQLQuery('RatingEqualsToPar', 'select /*all*/ * from customers where rating = ? order by code, city desc')] + [MVCNamedRQLQuery('RatingLessThanPar', 'lt(rating,%d);sort(+code,-city)')] + [MVCNamedRQLQuery('RatingEqualsToPar', 'eq(rating,%d);sort(+code,-city)')] TCustomer = class(TCustomEntity) private {$IFNDEF USE_SEQUENCES} @@ -408,6 +412,35 @@ type property Orders: TObjectList read GetOrders; end; + [MVCNameCase(ncLowerCase)] + [MVCEntityActions([eaRetrieve])] + [MVCNamedSQLQuery('CustomersInTheSameCity', + 'SELECT c.id, c.DESCRIPTION, c.city, c.code, c.rating, (SELECT count(*) - 1 FROM customers c2 WHERE c2.CITY = c.CITY) customers_in_the_same_city ' + + 'FROM CUSTOMERS c WHERE city IS NOT NULL AND city <> '''' ORDER BY customers_in_the_same_city')] + TCustomerStats = class(TCustomEntity) + private + [MVCTableField('id', [foPrimaryKey, foAutoGenerated])] + fID: NullableInt64; + [MVCTableField('code')] + fCode: NullableString; + [MVCTableField('description')] + fCompanyName: NullableString; + [MVCTableField('city')] + fCity: string; + [MVCTableField('rating')] + fRating: NullableInt32; + [MVCTableField('customers_in_the_same_city')] + fCustomersInTheSameCity: Int32; + public + property ID: NullableInt64 read fID write fID; + property Code: NullableString read fCode write fCode; + property CompanyName: NullableString read fCompanyName write fCompanyName; + property City: string read fCity write fCity; + property Rating: NullableInt32 read fRating write fRating; + property CustomersInTheSameCity: Int32 read fCustomersInTheSameCity write fCustomersInTheSameCity; + end; + + [MVCNameCase(ncLowerCase)] [MVCTable('customers')] TCustomerWithLogic = class(TCustomer) diff --git a/samples/activerecord_showcase/MainFormU.dfm b/samples/activerecord_showcase/MainFormU.dfm index c9e1704d..9b914f49 100644 --- a/samples/activerecord_showcase/MainFormU.dfm +++ b/samples/activerecord_showcase/MainFormU.dfm @@ -276,6 +276,15 @@ object MainForm: TMainForm TabOrder = 26 OnClick = btnNamedQueryClick end + object btnVirtualEntities: TButton + Left = 144 + Top = 522 + Width = 121 + Height = 34 + Caption = 'Virtual Entities' + TabOrder = 27 + OnClick = btnVirtualEntitiesClick + end object FDConnection1: TFDConnection Left = 312 Top = 40 diff --git a/samples/activerecord_showcase/MainFormU.pas b/samples/activerecord_showcase/MainFormU.pas index 08a1b6b1..1bff37e1 100644 --- a/samples/activerecord_showcase/MainFormU.pas +++ b/samples/activerecord_showcase/MainFormU.pas @@ -59,6 +59,7 @@ type btnSpeed: TButton; btnRefresh: TButton; btnNamedQuery: TButton; + btnVirtualEntities: TButton; procedure btnCRUDClick(Sender: TObject); procedure btnInheritanceClick(Sender: TObject); procedure btnMultiThreadingClick(Sender: TObject); @@ -88,6 +89,7 @@ type procedure btnSpeedClick(Sender: TObject); procedure btnRefreshClick(Sender: TObject); procedure btnNamedQueryClick(Sender: TObject); + procedure btnVirtualEntitiesClick(Sender: TObject); private procedure Log(const Value: string); procedure LoadCustomers; @@ -654,7 +656,7 @@ end; procedure TMainForm.btnNamedQueryClick(Sender: TObject); begin Log('** Named SQL Query'); - Log('Query: RatingLessThanPar'); + Log('QuerySQL: RatingLessThanPar'); var lCustomers := TMVCActiveRecord.SelectByNamedQuery('RatingLessThanPar', [4], [ftInteger]); try for var lCustomer in lCustomers do @@ -666,8 +668,8 @@ begin lCustomers.Free; end; - Log('Query: RatingEqualsToPar'); - lCustomers := TMVCActiveRecord.SelectByNamedQuery('RatingEqualsToPar', [1], [ftInteger]); + Log('QuerySQL: RatingEqualsToPar'); + lCustomers := TMVCActiveRecord.SelectByNamedQuery('RatingEqualsToPar', [3], [ftInteger]); try for var lCustomer in lCustomers do begin @@ -678,6 +680,32 @@ begin lCustomers.Free; end; + Log('** Named RQL Query'); + Log('QueryRQL: RatingLessThanPar'); + lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery('RatingLessThanPar', [4], 1000); + try + for var lCustomer in lCustomers do + begin + Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault])); + end; + finally + lCustomers.Free; + end; + + Log('QueryRQL: RatingEqualsToPar'); + lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery('RatingEqualsToPar', [3], 1000); + try + for var lCustomer in lCustomers do + begin + Log(Format('%4d - %8.5s - %s', [lCustomer.ID.ValueOrDefault, lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault])); + end; + finally + lCustomers.Free; + end; + + end; procedure TMainForm.btnNullablesClick(Sender: TObject); @@ -1681,6 +1709,24 @@ begin end; end; +procedure TMainForm.btnVirtualEntitiesClick(Sender: TObject); +begin + var lCustStats := TMVCActiveRecord.SelectByNamedQuery('CustomersInTheSameCity', [], []); + try + for var lCustomer in lCustStats do + begin + Log(Format('%4d - %8.5s - %s - (%d other customers in the same city)', [ + lCustomer.ID.ValueOrDefault, + lCustomer.Code.ValueOrDefault, + lCustomer.CompanyName.ValueOrDefault, + lCustomer.CustomersInTheSameCity + ])); + end; + finally + lCustStats.Free; + end; +end; + procedure TMainForm.btnWithSpacesClick(Sender: TObject); var lCustomer: TCustomerWithSpaces; diff --git a/sources/MVCFramework.ActiveRecord.pas b/sources/MVCFramework.ActiveRecord.pas index b91797c5..d46ed803 100644 --- a/sources/MVCFramework.ActiveRecord.pas +++ b/sources/MVCFramework.ActiveRecord.pas @@ -103,11 +103,18 @@ type procedure EndUpdates; end; - TQueryWithName = record + TSQLQueryWithName = record Name: String; - QueryText: String; + SQLText: String; + BackEnd: String; //TMVCActiveRecordBackEnd end; + TRQLQueryWithName = record + Name: String; + RQLText: String; + end; + + TFieldsMap = class(TObjectDictionary) private fWritableFieldsCount: Integer; @@ -142,7 +149,16 @@ type public Name: string; SQLQuery: String; - constructor Create(aName: string; aSQLSelect: String); + Backend: String; //TMVCActiveRecordBackEnd + constructor Create(aName: string; aSQLSelect: String); overload; + constructor Create(aName: string; aSQLSelect: String; aBackEnd: String); overload; + end; + + MVCNamedRQLQueryAttribute = class(MVCActiveRecordCustomAttribute) + public + Name: string; + RQLQuery: String; + constructor Create(aName: string; aRQL: String); end; MVCTableFieldAttribute = class(MVCActiveRecordCustomAttribute) @@ -214,7 +230,8 @@ type fPrimaryKeyOptions: TMVCActiveRecordFieldOptions; fPrimaryKeySequenceName: string; fPrimaryKeyFieldType: TFieldType; - fNamedSQLQueries: TArray; + fNamedSQLQueries: TArray; + fNamedRQLQueries: TArray; public constructor Create; destructor Destroy; override; @@ -239,7 +256,6 @@ type fBackendDriver: string; fTableMap: TMVCTableMap; function GetPartitionInfo: TPartitionInfo; - function GetBackEnd: string; function GetConnection: TFDConnection; procedure InitTableInfo; class function ExecQuery( @@ -356,6 +372,7 @@ type procedure EnsureConnection; procedure Assign(ActiveRecord: TMVCActiveRecord); virtual; procedure InvalidateConnection(const ReacquireAfterInvalidate: Boolean = false); + function GetBackEnd: string; /// /// Executes an Insert (pk is null) or an Update (pk is not null) /// @@ -387,7 +404,8 @@ type procedure RemoveChildren(const ChildObject: TObject); function GetPrimaryKeyFieldType: TFieldType; - function FindSQLQueryByName(const QueryName: String; out NamedSQLQuery: TQueryWithName): Boolean; + function FindSQLQueryByName(const QueryName: String; out NamedSQLQuery: TSQLQueryWithName): Boolean; + function FindRQLQueryByName(const QueryName: String; out NamedRQLQuery: TRQLQueryWithName): Boolean; property Attributes[const AttrName: string]: TValue read GetAttributes @@ -581,6 +599,16 @@ type const Params: array of Variant; const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions = []): TObjectList; + class function SelectRQLByNamedQuery( + const QueryName: String; + const Params: array of const; + const MaxRecordCount: Integer): TObjectList; + class function DeleteRQLByNamedQuery( + const QueryName: String; + const Params: array of const): Int64; + class function CountRQLByNamedQuery( + const QueryName: string; + const Params: array of const): Int64; end; IMVCEntitiesRegistry = interface @@ -1320,17 +1348,38 @@ begin end; end; -function TMVCActiveRecord.FindSQLQueryByName(const QueryName: String; - out NamedSQLQuery: TQueryWithName): Boolean; +function TMVCActiveRecord.FindRQLQueryByName(const QueryName: String; + out NamedRQLQuery: TRQLQueryWithName): Boolean; var I: Integer; +begin + for I := Low(fTableMap.fNamedRQLQueries) to High(fTableMap.fNamedRQLQueries) do + begin + if SameText(QueryName, fTableMap.fNamedRQLQueries[I].Name) then + begin + NamedRQLQuery := fTableMap.fNamedRQLQueries[I]; + Exit(True); + end; + end; + Result := False; +end; + +function TMVCActiveRecord.FindSQLQueryByName(const QueryName: String; + out NamedSQLQuery: TSQLQueryWithName): Boolean; +var + I: Integer; + lBackEnd: String; begin for I := Low(fTableMap.fNamedSQLQueries) to High(fTableMap.fNamedSQLQueries) do begin if SameText(QueryName, fTableMap.fNamedSQLQueries[I].Name) then begin - NamedSQLQuery := fTableMap.fNamedSQLQueries[I]; - Exit(True); + lBackEnd := fTableMap.fNamedSQLQueries[I].BackEnd; + if lBackEnd.IsEmpty or (lBackEnd = GetBackEnd) then + begin + NamedSQLQuery := fTableMap.fNamedSQLQueries[I]; + Exit(True); + end; end; end; Result := False; @@ -1351,6 +1400,7 @@ var lTableMap: TMVCTableMap; lPKCount: Integer; lNamedSQLQueryCount: Integer; + lNamedRQLQueryCount: Integer; begin if ActiveRecordTableMapRegistry.TryGetValue(Self, fTableMap) then begin @@ -1373,6 +1423,7 @@ begin lTableMap.fObjAttributes := lTableMap.fRTTIType.GetAttributes; lPKCount := 0; lNamedSQLQueryCount := Length(lTableMap.fNamedSQLQueries); + lNamedRQLQueryCount := Length(lTableMap.fNamedRQLQueries); for lAttribute in lTableMap.fObjAttributes do begin if lAttribute is MVCTableAttribute then @@ -1396,7 +1447,16 @@ begin Inc(lNamedSQLQueryCount); SetLength(lTableMap.fNamedSQLQueries, lNamedSQLQueryCount); lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].Name := MVCNamedSQLQueryAttribute(lAttribute).Name; - lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].QueryText := MVCNamedSQLQueryAttribute(lAttribute).SQLQuery; + lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].SQLText := MVCNamedSQLQueryAttribute(lAttribute).SQLQuery; + lTableMap.fNamedSQLQueries[lNamedSQLQueryCount - 1].BackEnd := MVCNamedSQLQueryAttribute(lAttribute).Backend; + Continue; + end; + if lAttribute is MVCNamedRQLQueryAttribute then + begin + Inc(lNamedRQLQueryCount); + SetLength(lTableMap.fNamedRQLQueries, lNamedRQLQueryCount); + lTableMap.fNamedRQLQueries[lNamedRQLQueryCount - 1].Name := MVCNamedRQLQueryAttribute(lAttribute).Name; + lTableMap.fNamedRQLQueries[lNamedRQLQueryCount - 1].RQLText := MVCNamedRQLQueryAttribute(lAttribute).RQLQuery; Continue; end; end; @@ -1795,6 +1855,26 @@ begin end; end; +class function TMVCActiveRecordHelper.SelectRQLByNamedQuery( + const QueryName: string; + const Params: array of const; + const MaxRecordCount: Integer): TObjectList; +var + lT: T; + lRQLQuery: TRQLQueryWithName; +begin + lT := T.Create; + try + if not lT.FindRQLQueryByName(QueryName, lRQLQuery) then + begin + raise EMVCActiveRecord.CreateFmt('NamedRQLQuery not found: %s', [QueryName]); + end; + Result := SelectRQL(Format(lRQLQuery.RQLText, Params), MaxRecordCount); + finally + lT.Free; + end; +end; + class function TMVCActiveRecordHelper.Where(const SQLWhere: string; const Params: array of Variant; const ParamTypes: array of TFieldType; const OutList: TObjectList): UInt32; @@ -1925,11 +2005,49 @@ begin Result := TMVCActiveRecord.Count(TMVCActiveRecordClass(T), RQL); end; +class function TMVCActiveRecordHelper.CountRQLByNamedQuery( + const QueryName: string; + const Params: array of const): Int64; +var + lRQLQuery: TRQLQueryWithName; + lT: T; +begin + lT := T.Create; + try + if not lT.FindRQLQueryByName(QueryName, lRQLQuery) then + begin + raise EMVCActiveRecord.CreateFmt('NamedRQLQuery not found: %s', [QueryName]); + end; + Result := Count(Format(lRQLQuery.RQLText, Params)); + finally + lT.Free; + end; +end; + class function TMVCActiveRecordHelper.DeleteRQL(const RQL: string): int64; begin Result := TMVCActiveRecord.DeleteRQL(TMVCActiveRecordClass(T), RQL); end; +class function TMVCActiveRecordHelper.DeleteRQLByNamedQuery( + const QueryName: String; + const Params: array of const): Int64; +var + lRQLQuery: TRQLQueryWithName; + lT: T; +begin + lT := T.Create; + try + if not lT.FindRQLQueryByName(QueryName, lRQLQuery) then + begin + raise EMVCActiveRecord.CreateFmt('NamedRQLQuery not found: %s', [QueryName]); + end; + Result := DeleteRQL(Format(lRQLQuery.RQLText, Params)); + finally + lT.Free; + end; +end; + class function TMVCActiveRecord.CurrentConnection: TFDConnection; begin Result := ActiveRecordConnectionsRegistry.GetCurrent; @@ -2696,7 +2814,7 @@ class function TMVCActiveRecordHelper.SelectByNamedQuery( const Options: TMVCActiveRecordLoadOptions): TObjectList; var lT: T; - lSQLQuery: TQueryWithName; + lSQLQuery: TSQLQueryWithName; begin lT := T.Create; try @@ -2704,7 +2822,7 @@ begin begin raise EMVCActiveRecord.CreateFmt('NamedSQLQuery not found: %s', [QueryName]); end; - Result := Select(lSQLQuery.QueryText, Params, ParamTypes, Options); + Result := Select(lSQLQuery.SQLText, Params, ParamTypes, Options); finally lT.Free; end; @@ -4283,10 +4401,26 @@ end; { MVCNamedSQLQueryAttribute } constructor MVCNamedSQLQueryAttribute.Create(aName, aSQLSelect: String); +begin + Create(aName, aSQLSelect, ''); +end; + +constructor MVCNamedSQLQueryAttribute.Create(aName, aSQLSelect, + aBackEnd: String); begin inherited Create; Name := aName; SQLQuery := aSQLSelect; + BackEnd := aBackEnd; +end; + +{ MVCNamedRQLQueryAttribute } + +constructor MVCNamedRQLQueryAttribute.Create(aName, aRQL: String); +begin + inherited Create; + Name := aName; + RQLQuery := aRQL; end; initialization diff --git a/unittests/general/Several/ActiveRecordTestsU.pas b/unittests/general/Several/ActiveRecordTestsU.pas index d72553e7..4a2aecc1 100644 --- a/unittests/general/Several/ActiveRecordTestsU.pas +++ b/unittests/general/Several/ActiveRecordTestsU.pas @@ -70,12 +70,20 @@ type [Test] procedure TestSelectWithExceptions; [Test] + procedure TestNamedQuerySQL; + [Test] + procedure TestNamedQuerySQLByBackEnd; + [Test] procedure TestStore; [Test] procedure TestLifeCycle; [Test] procedure TestRQL; [Test] + procedure TestNamedQueryRQL; + [Test] + procedure TestNamedQueryRQLWithExceptions; + [Test] procedure TestRQLWithMVCNameAsAttribute; [Test] procedure TestRQLWithBoolean; @@ -1170,6 +1178,68 @@ begin Assert.AreEqual(Trunc(20 * 30), TMVCActiveRecord.Count(TCustomerWithLF)); end; +procedure TTestActiveRecordBase.TestNamedQueryRQL; +var + lCustomers: TObjectList; +begin + Assert.AreEqual(Int64(0), TMVCActiveRecord.Count(TCustomer)); + LoadData; + lCustomers := TMVCActiveRecord.SelectRQLByNamedQuery('CityRomeOrLondon', [], MAXINT); + try + Assert.AreEqual(240, lCustomers.Count); + for var lCustomer in lCustomers do + begin + Assert.IsMatch('^(Rome|London)$', lCustomer.City); + end; + finally + lCustomers.Free; + end; + TMVCActiveRecord.DeleteRQLByNamedQuery('CityRomeOrLondon', []); + Assert.AreEqual(Int64(0), TMVCActiveRecord.CountRQLByNamedQuery('CityRomeOrLondon', [])); +end; + +procedure TTestActiveRecordBase.TestNamedQueryRQLWithExceptions; +begin + Assert.WillRaiseWithMessage( + procedure + begin + TMVCActiveRecord.SelectRQLByNamedQuery('WrongQueryName', [1,2,3], MAXINT); + end, nil, 'NamedRQLQuery not found: WrongQueryName'); + + Assert.WillRaiseWithMessage( + procedure + begin + TMVCActiveRecord.DeleteRQLByNamedQuery('WrongQueryName', []); + end, nil, 'NamedRQLQuery not found: WrongQueryName'); +end; + +procedure TTestActiveRecordBase.TestNamedQuerySQL; +begin + Assert.AreEqual(Int64(0), TMVCActiveRecord.Count(TCustomer)); + LoadData; + var lCustomers := TMVCActiveRecord.SelectByNamedQuery('ByTwoCities', ['Rome', 'London'], [ftString, ftString]); + try + Assert.AreEqual(240, lCustomers.Count); + for var lCustomer in lCustomers do + begin + Assert.IsMatch('^(Rome|London)$', lCustomer.City); + end; + finally + lCustomers.Free; + end; +end; + +procedure TTestActiveRecordBase.TestNamedQuerySQLByBackEnd; +begin + var lList := TMVCActiveRecord.SelectByNamedQuery('get_backend_name', [],[]); + try + Assert.AreEqual(1, lList.Count); + Assert.AreEqual(lList.First.GetBackEnd, lList.First.BackEndName); + finally + lList.Free; + end; +end; + procedure TTestActiveRecordBase.TestNullables; var lTest: TNullablesTest; diff --git a/unittests/general/Several/BOs.pas b/unittests/general/Several/BOs.pas index 10aceae4..88ce22bb 100644 --- a/unittests/general/Several/BOs.pas +++ b/unittests/general/Several/BOs.pas @@ -101,6 +101,8 @@ const type [MVCTable('customers')] + [MVCNamedRQLQuery('CityRomeOrLondon','or(eq(City, "Rome"),eq(City, "London"))')] + [MVCNamedSQLQuery('ByTwoCities','select * from customers where city = ? or city = ?')] TCustomer = class(TMVCActiveRecord) private [MVCTableField('id', [foPrimaryKey, foAutoGenerated])] @@ -661,6 +663,19 @@ type destructor Destroy; override; end; + [MVCEntityActions([eaRetrieve])] + [MVCNamedSQLQuery('get_backend_name', 'select ''firebird'' backendname from rdb$database', TMVCActiveRecordBackEnd.FirebirdSQL)] + [MVCNamedSQLQuery('get_backend_name', 'select ''postgresql'' backendname', TMVCActiveRecordBackEnd.PostgreSQL)] + [MVCNamedSQLQuery('get_backend_name', 'select ''sqlite'' backendname', TMVCActiveRecordBackEnd.SQLite)] + TDummyEntity = class(TMVCActiveRecord) + private + [MVCTableField('backendname')] + FBackEndName: String; + procedure SetBackEndName(const Value: String); + public + property BackEndName: String read FBackEndName write SetBackEndName; + end; + function GetMyObject: TMyObject; function GetMyObjectWithTValue: TMyObjectWithTValue; function GetMyObjectWithStream: TMyStreamObject; @@ -1432,6 +1447,13 @@ begin end; +{ TDummyEntity } + +procedure TDummyEntity.SetBackEndName(const Value: String); +begin + FBackEndName := Value; +end; + initialization ActiveRecordMappingRegistry.AddEntity('customers', TCustomer); From cbdb7b684f0414b708a5f520c2a42cef1e04a212 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Wed, 9 Aug 2023 15:57:28 +0200 Subject: [PATCH 24/31] Improved ISAPI sample --- samples/ISAPI/ISAPI/isapiapp.dpr | 30 +- samples/ISAPI/ISAPI/isapiapp.dproj | 283 ++--- samples/ISAPI/StandAlone/StandAloneServer.dpr | 55 - .../ISAPI/StandAlone/StandAloneServer.dproj | 1027 ----------------- sources/MVCFramework.DotEnv.pas | 2 +- sources/MVCFramework.Logger.pas | 42 +- 6 files changed, 195 insertions(+), 1244 deletions(-) delete mode 100644 samples/ISAPI/StandAlone/StandAloneServer.dpr delete mode 100644 samples/ISAPI/StandAlone/StandAloneServer.dproj diff --git a/samples/ISAPI/ISAPI/isapiapp.dpr b/samples/ISAPI/ISAPI/isapiapp.dpr index 9352efa0..5af55ee6 100644 --- a/samples/ISAPI/ISAPI/isapiapp.dpr +++ b/samples/ISAPI/ISAPI/isapiapp.dpr @@ -1,22 +1,28 @@ library isapiapp; - - - - uses Winapi.ActiveX, System.Win.ComObj, + MVCFramework.DotEnv, + MVCFramework.Commons, + MVCFramework.Logger, Web.WebBroker, Web.Win.ISAPIApp, Web.Win.ISAPIThreadPool, MainDataModuleUnit in '..\..\WineCellarSample\winecellarserver\MainDataModuleUnit.pas' {WineCellarDataModule: TDataModule}, MainWebModuleUnit in '..\..\WineCellarSample\winecellarserver\MainWebModuleUnit.pas' {wm: TWebModule}, WinesBO in '..\..\WineCellarSample\winecellarserver\WinesBO.pas', - WineCellarAppControllerU in '..\..\WineCellarSample\winecellarserver\WineCellarAppControllerU.pas'; + WineCellarAppControllerU in '..\..\WineCellarSample\winecellarserver\WineCellarAppControllerU.pas', + Winapi.Windows; {$R *.res} +function TerminateExtension(dwFlags: DWORD): BOOL; stdcall; +begin + ReleaseGlobalLogger; + Result := Web.Win.ISAPIThreadPool.TerminateExtension(dwFlags); +end; + exports GetExtensionVersion, HttpExtensionProc, @@ -26,5 +32,19 @@ begin CoInitFlags := COINIT_MULTITHREADED; Application.Initialize; Application.WebModuleClass := WebModuleClass; + dotEnvConfigure( + function: IMVCDotEnv + begin + Result := NewDotEnv + .WithStrategy(TMVCDotEnvPriority.FileThenEnv) + //if available, by default, loads default environment (.env) + .UseProfile('test') //if available loads the test environment (.env.test) + .UseProfile('prod') //if available loads the prod environment (.env.prod) + .UseLogger(procedure(LogItem: String) + begin + LogW('dotEnv: ' + LogItem); + end) + .Build(); //uses the executable folder to look for .env* files + end); Application.Run; end. diff --git a/samples/ISAPI/ISAPI/isapiapp.dproj b/samples/ISAPI/ISAPI/isapiapp.dproj index aa952676..68a11e56 100644 --- a/samples/ISAPI/ISAPI/isapiapp.dproj +++ b/samples/ISAPI/ISAPI/isapiapp.dproj @@ -6,8 +6,8 @@ isapiapp.dpr True Debug - Win32 - 1 + Win64 + 2 Library @@ -34,6 +34,12 @@ true true + + true + Cfg_1 + true + true + true Base @@ -66,6 +72,14 @@ FireDACSqliteDriver;DBXSqliteDriver;FireDACPgDriver;fmx;TreeViewPresenter;IndySystem;TeeDB;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;IndyIPCommon;CloudService;DBXMSSQLDriver;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;inetdbxpress;FireDACDb2Driver;adortl;DataBindingsVCL;FireDACASADriver;bindcompfmx;FireDACODBCDriver;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DataBindings;DBXOdbcDriver;vclFireDAC;xmlrtl;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindengine;vclactnband;soaprtl;bindcompdbx;FMXTee;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;fmxinfopower;VclSmp;FireDACMSSQLDriver;FireDAC;VCLRESTComponents;Intraweb;DBXInformixDriver;DataSnapConnectors;FireDACDataSnapDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;FireDACMySQLDriver;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;VirtualTreesR;FireDACMSAccDriver;DataSnapIndy10ServerTransport;dbexpress;IndyIPClient;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + ..\bin + (None) + none DEBUG;$(DCC_Define) @@ -82,6 +96,15 @@ 1033 false + + true + 1033 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + (None) + none + C:\Windows\System32\inetsrv\w3wp.exe + -debug + false RELEASE;$(DCC_Define) @@ -94,12 +117,10 @@
WineCellarDataModule
- dfm TDataModule
wm
- dfm TWebModule
@@ -175,10 +196,10 @@ isapiapp.dpr - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components @@ -579,6 +600,127 @@ 0 + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset @@ -779,127 +921,6 @@ 1 - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - @@ -914,8 +935,8 @@ - True - False + False + True 12 diff --git a/samples/ISAPI/StandAlone/StandAloneServer.dpr b/samples/ISAPI/StandAlone/StandAloneServer.dpr deleted file mode 100644 index 4477d09f..00000000 --- a/samples/ISAPI/StandAlone/StandAloneServer.dpr +++ /dev/null @@ -1,55 +0,0 @@ -program StandAloneServer; -{$APPTYPE CONSOLE} - - -uses - System.SysUtils, - Winapi.Windows, - IdHTTPWebBrokerBridge, - Web.WebReq, - Web.WebBroker, - WebModuleU in '..\WebModules\WebModuleU.pas' {WebModule1: TWebModule} , - RoutingSampleControllerU in '..\Controllers\RoutingSampleControllerU.pas', - BusinessObjectsU in '..\BO\BusinessObjectsU.pas'; - -{$R *.res} - - -procedure RunServer(APort: Integer); -var - LInputRecord: TInputRecord; - LEvent: DWord; - LHandle: THandle; - LServer: TIdHTTPWebBrokerBridge; -begin - Writeln(Format('Starting HTTP Server or port %d', [APort])); - LServer := TIdHTTPWebBrokerBridge.Create(nil); - try - LServer.DefaultPort := APort; - LServer.Active := True; - Writeln('Press ESC to stop the server'); - LHandle := GetStdHandle(STD_INPUT_HANDLE); - while True do - begin - Win32Check(ReadConsoleInput(LHandle, LInputRecord, 1, LEvent)); - if (LInputRecord.EventType = KEY_EVENT) and - LInputRecord.Event.KeyEvent.bKeyDown and - (LInputRecord.Event.KeyEvent.wVirtualKeyCode = VK_ESCAPE) then - break; - end; - finally - LServer.Free; - end; -end; - -begin - try - if WebRequestHandler <> nil then - WebRequestHandler.WebModuleClass := WebModuleClass; - RunServer(8080); - except - on E: Exception do - Writeln(E.ClassName, ': ', E.Message); - end - -end. diff --git a/samples/ISAPI/StandAlone/StandAloneServer.dproj b/samples/ISAPI/StandAlone/StandAloneServer.dproj deleted file mode 100644 index 52a2c519..00000000 --- a/samples/ISAPI/StandAlone/StandAloneServer.dproj +++ /dev/null @@ -1,1027 +0,0 @@ - - - {89FED123-CDD0-460A-9CC6-5810B281BF84} - 18.8 - VCL - StandAloneServer.dpr - True - Debug - Win32 - 1 - Console - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_1 - true - true - - - true - Base - true - - - StandAloneServer - CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) - $(BDS)\bin\delphi_PROJECTICON.ico - 1040 - ..\..\..\sources;..\..\..\lib\delphistompclient;..\..\..\lib\loggerpro;..\..\..\lib\dmustache;$(DCC_UnitSearchPath) - $(BDS)\bin\delphi_PROJECTICNS.icns - System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) - .\$(Platform)\$(Config) - .\$(Platform)\$(Config) - false - false - false - false - false - - - true - Base - true - true - true - $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png - $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png - true - true - true - $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png - $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png - true - $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png - true - $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png - android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar - $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png - $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png - true - true - Debug - true - - - true - Base - true - Debug - - - None - ..\bin - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - 1033 - FireDACSqliteDriver;TsiLang_XE5r;DBXSqliteDriver;FireDACPgDriver;fmx;TreeViewPresenter;IndySystem;i18n;TeeDB;frx19;vclib;inetdbbde;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DPFAndroidPackagesXE5;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;i18nDB;fmxase;vcl;IndyCore;IndyIPCommon;CloudService;DBXMSSQLDriver;FmxTeeUI;FireDACIBDriver;CodeSiteExpressPkg;DataSnapFireDAC;FireDACDBXDriver;inetdbxpress;FireDACDb2Driver;adortl;CustomAdaptersMDPackage;DataBindingsVCL;FireDACASADriver;bindcompfmx;vcldbx;FireDACODBCDriver;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DataBindings;DBXOdbcDriver;vclFireDAC;CPortLibDXE;xmlrtl;svnui;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindengine;vclactnband;soaprtl;bindcompdbx;FMXTee;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;fmxinfopower;VclSmp;FireDACMSSQLDriver;FireDAC;VCLRESTComponents;Intraweb;DBXInformixDriver;DataSnapConnectors;FireDACDataSnapDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;FireDACMySQLDriver;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;bdertl;VirtualTreesR;FireDACMSAccDriver;DataSnapIndy10ServerTransport;dbexpress;IndyIPClient;$(DCC_UsePackage) - CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(ModuleName);FileDescription=$(ModuleName);ProductName=$(ModuleName) - - - FireDACSqliteDriver;DBXSqliteDriver;FireDACPgDriver;fmx;TreeViewPresenter;IndySystem;TeeDB;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;IndyIPCommon;CloudService;DBXMSSQLDriver;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;inetdbxpress;FireDACDb2Driver;adortl;DataBindingsVCL;FireDACASADriver;bindcompfmx;FireDACODBCDriver;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DataBindings;DBXOdbcDriver;vclFireDAC;xmlrtl;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindengine;vclactnband;soaprtl;bindcompdbx;FMXTee;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;fmxinfopower;VclSmp;FireDACMSSQLDriver;FireDAC;VCLRESTComponents;Intraweb;DBXInformixDriver;DataSnapConnectors;FireDACDataSnapDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;FireDACMySQLDriver;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;VirtualTreesR;FireDACMSAccDriver;DataSnapIndy10ServerTransport;dbexpress;IndyIPClient;$(DCC_UsePackage) - - - DEBUG;$(DCC_Define) - true - false - true - true - true - - - CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) - 1033 - false - - - false - RELEASE;$(DCC_Define) - 0 - 0 - - - - MainSource - - -
WebModule1
- dfm - TWebModule -
- - - - Cfg_2 - Base - - - Base - - - Cfg_1 - Base - -
- - Delphi.Personality.12 - - - - - False - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1040 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - StandAloneServer.dpr - - - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - - - - 1 - - - 0 - - - - - classes - 1 - - - classes - 1 - - - - - res\xml - 1 - - - res\xml - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\armeabi - 1 - - - library\lib\armeabi - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\mips - 1 - - - library\lib\mips - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\values-v21 - 1 - - - res\values-v21 - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-ldpi - 1 - - - res\drawable-ldpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-small - 1 - - - res\drawable-small - 1 - - - - - res\drawable-normal - 1 - - - res\drawable-normal - 1 - - - - - res\drawable-large - 1 - - - res\drawable-large - 1 - - - - - res\drawable-xlarge - 1 - - - res\drawable-xlarge - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - 1 - - - 1 - - - 0 - - - - - 1 - .framework - - - 1 - .framework - - - 0 - - - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .dll;.bpl - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .bpl - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 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 - - - 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 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - 1 - - - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - - - - - - - - - - - False - False - True - False - - - 12 - - - - -
diff --git a/sources/MVCFramework.DotEnv.pas b/sources/MVCFramework.DotEnv.pas index e8882ff0..f9c19f2f 100644 --- a/sources/MVCFramework.DotEnv.pas +++ b/sources/MVCFramework.DotEnv.pas @@ -204,7 +204,7 @@ begin begin fEnvPath := TPath.Combine(fEnvPath, DotEnvDirectory); end; - DoLog('Path = ' + DotEnvDirectory); + DoLog('Path = ' + fEnvPath); fEnvDict.Clear; lAllProfiles := ['default'] + fProfiles.ToArray(); DoLog('Active profile/s priority = [' + String.Join(',', lAllProfiles) + ']'); diff --git a/sources/MVCFramework.Logger.pas b/sources/MVCFramework.Logger.pas index c3ef8813..a5355c19 100644 --- a/sources/MVCFramework.Logger.pas +++ b/sources/MVCFramework.Logger.pas @@ -194,14 +194,6 @@ begin LogE(E.ClassName + ': ' + AMessage); end; -// procedure LogException( -// const AException: Exception; -// const AMessage: string); -// begin -// Log.Error(Format('[%s] %s (Custom message: "%s")', [AException.ClassName, -// AException.Message, AMessage]), LOGGERPRO_TAG); -// end; - procedure LogEnterMethod(const AMethodName: string); begin LogI('>> ' + AMethodName); @@ -266,27 +258,27 @@ end; procedure SetDefaultLogger(const aLogWriter: ILogWriter); begin - if gDefaultLogger = nil then - begin - TMonitor.Enter(gLock); // double check here - try - if gDefaultLogger = nil then + if gDefaultLogger = nil then + begin + TMonitor.Enter(gLock); // double check here + try + if gDefaultLogger = nil then + begin + if aLogWriter <> nil then begin - if aLogWriter <> nil then - begin - gDefaultLogger := aLogWriter; - Log.Info('Custom Logger initialized', LOGGERPRO_TAG); - end - else - begin - InitializeDefaultLogger; - Log.Info('Default Logger initialized', LOGGERPRO_TAG); - end; + gDefaultLogger := aLogWriter; + Log.Info('Custom Logger initialized', LOGGERPRO_TAG); + end + else + begin + InitializeDefaultLogger; + Log.Info('Default Logger initialized', LOGGERPRO_TAG); end; - finally - TMonitor.Exit(gLock); end; + finally + TMonitor.Exit(gLock); end; + end; end; procedure InitializeDefaultLogger; From 8043616977f54474150ba718f6c83bc4751ad25c Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Wed, 9 Aug 2023 15:58:19 +0200 Subject: [PATCH 25/31] Improved ISAPI sample --- samples/ISAPI/ProjectGroup.groupproj | 48 ++ samples/ISAPI/StandAlone/ConsoleApp.dpr | 65 ++ samples/ISAPI/StandAlone/ConsoleApp.dproj | 980 ++++++++++++++++++++++ samples/ISAPI/bin/.env | 1 + samples/ISAPI/bin/web.config | 18 + 5 files changed, 1112 insertions(+) create mode 100644 samples/ISAPI/ProjectGroup.groupproj create mode 100644 samples/ISAPI/StandAlone/ConsoleApp.dpr create mode 100644 samples/ISAPI/StandAlone/ConsoleApp.dproj create mode 100644 samples/ISAPI/bin/.env create mode 100644 samples/ISAPI/bin/web.config diff --git a/samples/ISAPI/ProjectGroup.groupproj b/samples/ISAPI/ProjectGroup.groupproj new file mode 100644 index 00000000..91db9ac1 --- /dev/null +++ b/samples/ISAPI/ProjectGroup.groupproj @@ -0,0 +1,48 @@ + + + {5EA2FE29-4523-4296-8CFA-94B6AC904435} + + + + + + + + + + + Default.Personality.12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/ISAPI/StandAlone/ConsoleApp.dpr b/samples/ISAPI/StandAlone/ConsoleApp.dpr new file mode 100644 index 00000000..561ffb2f --- /dev/null +++ b/samples/ISAPI/StandAlone/ConsoleApp.dpr @@ -0,0 +1,65 @@ +program ConsoleApp; +{$APPTYPE CONSOLE} + + +uses + MVCFramework, + MVCFramework.Commons, + MVCFramework.Signal, + MVCFramework.DotEnv, + MVCFramework.Logger, + System.SysUtils, + Winapi.Windows, + IdHTTPWebBrokerBridge, + Web.WebReq, + Web.WebBroker, + WinesBO in '..\..\WineCellarSample\winecellarserver\WinesBO.pas', + WineCellarAppControllerU in '..\..\WineCellarSample\winecellarserver\WineCellarAppControllerU.pas', + MainWebModuleUnit in '..\..\WineCellarSample\winecellarserver\MainWebModuleUnit.pas' {wm: TWebModule}, + MainDataModuleUnit in '..\..\WineCellarSample\winecellarserver\MainDataModuleUnit.pas' {WineCellarDataModule: TDataModule}; + +{$R *.res} + + +procedure RunServer(APort: Integer); +var + LServer: TIdHTTPWebBrokerBridge; +begin + Writeln(Format('Starting HTTP Server or port %d', [APort])); + LServer := TIdHTTPWebBrokerBridge.Create(nil); + try + LServer.DefaultPort := APort; + LServer.Active := True; + Write('CTRL+C to stop the server'); + WaitForTerminationSignal; + EnterInShutdownState; + finally + LServer.Free; + end; +end; + +begin + try + if WebRequestHandler <> nil then + WebRequestHandler.WebModuleClass := WebModuleClass; + dotEnvConfigure( + function: IMVCDotEnv + begin + Result := NewDotEnv + .WithStrategy(TMVCDotEnvPriority.FileThenEnv) + //if available, by default, loads default environment (.env) + .UseProfile('test') //if available loads the test environment (.env.test) + .UseProfile('prod') //if available loads the prod environment (.env.prod) + .UseLogger(procedure(LogItem: String) + begin + LogW('dotEnv: ' + LogItem); + end) + .Build(); //uses the executable folder to look for .env* files + end); + RunServer(8080); + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end + +end. diff --git a/samples/ISAPI/StandAlone/ConsoleApp.dproj b/samples/ISAPI/StandAlone/ConsoleApp.dproj new file mode 100644 index 00000000..3de05e42 --- /dev/null +++ b/samples/ISAPI/StandAlone/ConsoleApp.dproj @@ -0,0 +1,980 @@ + + + {89FED123-CDD0-460A-9CC6-5810B281BF84} + 19.5 + VCL + ConsoleApp.dpr + True + Debug + Win64 + 2 + Console + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + ConsoleApp + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + $(BDS)\bin\delphi_PROJECTICON.ico + 1040 + ..\..\..\sources;..\..\..\lib\delphistompclient;..\..\..\lib\loggerpro;..\..\..\lib\dmustache;$(DCC_UnitSearchPath) + $(BDS)\bin\delphi_PROJECTICNS.icns + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + Base + true + true + true + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png + true + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png + true + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png + android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar + $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= + $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png + true + true + Debug + true + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png + + + None + ..\bin + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + 1033 + FireDACSqliteDriver;TsiLang_XE5r;DBXSqliteDriver;FireDACPgDriver;fmx;TreeViewPresenter;IndySystem;i18n;TeeDB;frx19;vclib;inetdbbde;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DPFAndroidPackagesXE5;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;i18nDB;fmxase;vcl;IndyCore;IndyIPCommon;CloudService;DBXMSSQLDriver;FmxTeeUI;FireDACIBDriver;CodeSiteExpressPkg;DataSnapFireDAC;FireDACDBXDriver;inetdbxpress;FireDACDb2Driver;adortl;CustomAdaptersMDPackage;DataBindingsVCL;FireDACASADriver;bindcompfmx;vcldbx;FireDACODBCDriver;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DataBindings;DBXOdbcDriver;vclFireDAC;CPortLibDXE;xmlrtl;svnui;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindengine;vclactnband;soaprtl;bindcompdbx;FMXTee;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;fmxinfopower;VclSmp;FireDACMSSQLDriver;FireDAC;VCLRESTComponents;Intraweb;DBXInformixDriver;DataSnapConnectors;FireDACDataSnapDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;FireDACMySQLDriver;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;bdertl;VirtualTreesR;FireDACMSAccDriver;DataSnapIndy10ServerTransport;dbexpress;IndyIPClient;$(DCC_UsePackage) + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(ModuleName);FileDescription=$(ModuleName);ProductName=$(ModuleName) + + + FireDACSqliteDriver;DBXSqliteDriver;FireDACPgDriver;fmx;TreeViewPresenter;IndySystem;TeeDB;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;IndyIPCommon;CloudService;DBXMSSQLDriver;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;inetdbxpress;FireDACDb2Driver;adortl;DataBindingsVCL;FireDACASADriver;bindcompfmx;FireDACODBCDriver;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DataBindings;DBXOdbcDriver;vclFireDAC;xmlrtl;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindengine;vclactnband;soaprtl;bindcompdbx;FMXTee;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;fmxinfopower;VclSmp;FireDACMSSQLDriver;FireDAC;VCLRESTComponents;Intraweb;DBXInformixDriver;DataSnapConnectors;FireDACDataSnapDriver;dsnapcon;DBXFirebirdDriver;inet;fmxobj;FireDACMySQLDriver;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;VirtualTreesR;FireDACMSAccDriver;DataSnapIndy10ServerTransport;dbexpress;IndyIPClient;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + ..\bin + (None) + none + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + 1033 + false + + + 1033 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + none + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + + +
wm
+ dfm + TWebModule +
+ +
WineCellarDataModule
+ dfm + TDataModule +
+ + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + Delphi.Personality.12 + + + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1040 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + ConsoleApp.dpr + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + ConsoleApp.exe + true + + + + + ConsoleApp.rsm + true + + + + + 1 + + + 0 + + + + + classes + 64 + + + classes + 64 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + 1 + + + 0 + + + + + 1 + .framework + + + 1 + .framework + + + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + False + False + True + + + 12 + + + + +
diff --git a/samples/ISAPI/bin/.env b/samples/ISAPI/bin/.env new file mode 100644 index 00000000..5d07214b --- /dev/null +++ b/samples/ISAPI/bin/.env @@ -0,0 +1 @@ +database.path = C:\DEV\dmvcframework\samples\WineCellarSample\winecellarserver\WINES_FB30.FDB \ No newline at end of file diff --git a/samples/ISAPI/bin/web.config b/samples/ISAPI/bin/web.config new file mode 100644 index 00000000..d08c7ca0 --- /dev/null +++ b/samples/ISAPI/bin/web.config @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From 85eef8920f1765c53d66756138376f6d46fd2c0b Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Sat, 12 Aug 2023 01:24:10 +0200 Subject: [PATCH 26/31] Added server side session with file persistence --- samples/session_file_based/AppControllerU.pas | 102 ++ .../FileBasedSessionSample.dpr | 55 ++ .../FileBasedSessionSample.dproj | 899 ++++++++++++++++++ samples/session_file_based/WebModuleUnit1.dfm | 11 + samples/session_file_based/WebModuleUnit1.pas | 44 + sources/MVCFramework.Session.pas | 263 ++++- sources/MVCFramework.pas | 91 +- 7 files changed, 1403 insertions(+), 62 deletions(-) create mode 100644 samples/session_file_based/AppControllerU.pas create mode 100644 samples/session_file_based/FileBasedSessionSample.dpr create mode 100644 samples/session_file_based/FileBasedSessionSample.dproj create mode 100644 samples/session_file_based/WebModuleUnit1.dfm create mode 100644 samples/session_file_based/WebModuleUnit1.pas diff --git a/samples/session_file_based/AppControllerU.pas b/samples/session_file_based/AppControllerU.pas new file mode 100644 index 00000000..bdac9165 --- /dev/null +++ b/samples/session_file_based/AppControllerU.pas @@ -0,0 +1,102 @@ +unit AppControllerU; + +interface + +uses + MVCFramework, + MVCFramework.Commons, + MVCFramework.Logger; + +type + [MVCPath('/')] + TApp1MainController = class(TMVCController) + public + [MVCPath('/name')] + [MVCHTTPMethod([httpGET])] + procedure Index; + + [MVCPath('/list')] + [MVCHTTPMethod([httpGET])] + procedure GetCustomSessionData; + + [MVCPath('/login/($username)')] + [MVCHTTPMethod([httpGET])] + procedure DoLogin(username: String); + + [MVCPath('/fruit/($nameOfFruit)')] + [MVCHTTPMethod([httpGET])] + procedure RegisterFruit(nameOfFruit: String); + + [MVCPath('/logout')] + [MVCHTTPMethod([httpGET])] + procedure DoLogout; + + end; + +implementation + +uses + System.SysUtils, + System.Classes; + +{ TApp1MainController } + +procedure TApp1MainController.DoLogin(username: String); +begin + Session['username'] := username; + ResponseStream + .AppendLine('Logged as ' + username) + .AppendLine + .AppendLine('in address of browser type: ') + .AppendLine('http://localhost:8080/list to check the current values in session ') + .AppendLine('http://localhost:8080/fruit/apple to register apple ') + .AppendLine('http://localhost:8080/fruit/banana to register banana ') + .AppendLine('http://localhost:8080/logout to end session ') + .AppendLine('http://localhost:8080/login/johndoe to login as johndoe'); + RenderResponseStream; +end; + +procedure TApp1MainController.RegisterFruit(nameOfFruit: String); +begin + Session[nameOfFruit] := nameOfFruit; + Redirect('/list'); +end; + +procedure TApp1MainController.DoLogout; +begin + Context.SessionStop(false); + Render('Logout'); +end; + +procedure TApp1MainController.GetCustomSessionData; +var + I: Integer; + lList: TArray; +begin + lList := Session.Keys; + ResponseStream.AppendLine('List of fruits:'); + for I := 0 to Length(lList) - 1 do + begin + ResponseStream.AppendLine(IntToStr(I + 1) + '-' + Session[lList[I]]); + end; + RenderResponseStream; +end; + +procedure TApp1MainController.Index; +begin + ContentType := TMVCMediaType.TEXT_PLAIN; + + // do not create session if not already created + if Context.SessionStarted then + begin + // automaticaly create the session + Render('Session[''username''] = ' + Session['username']); + end + else + begin + Render(400, 'Session not created. Do login first'); + end; +end; + +end. + diff --git a/samples/session_file_based/FileBasedSessionSample.dpr b/samples/session_file_based/FileBasedSessionSample.dpr new file mode 100644 index 00000000..bf342dbd --- /dev/null +++ b/samples/session_file_based/FileBasedSessionSample.dpr @@ -0,0 +1,55 @@ +program FileBasedSessionSample; + +{$APPTYPE CONSOLE} + + +uses + System.SysUtils, + MVCFramework, + MVCFramework.Signal, + {$IFDEF MSWINDOWS} + Winapi.Windows, + Winapi.ShellAPI, + {$ENDIF } + Web.WebReq, + Web.WebBroker, + IdHTTPWebBrokerBridge, + WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule}, + AppControllerU in 'AppControllerU.pas'; + +{$R *.res} + + +procedure RunServer(APort: Integer); +var + LServer: TIdHTTPWebBrokerBridge; +begin + Writeln(Format('Starting HTTP Server or port %d', [APort])); + LServer := TIdHTTPWebBrokerBridge.Create(nil); + try + LServer.DefaultPort := APort; + LServer.Active := True; + {$IFDEF MSWINDOWS} + //ShellExecute(0, 'open', PChar('http://localhost:' + IntToStr(APort) + '/login/john'), nil, nil, SW_SHOW); + {$ENDIF} + Writeln('CTRL+C to stop the server'); + WaitForTerminationSignal; + EnterInShutdownState; + finally + LServer.Free; + end; +end; + +begin + ReportMemoryLeaksOnShutdown := True; + try + if WebRequestHandler <> nil then + WebRequestHandler.WebModuleClass := WebModuleClass; + WebRequestHandlerProc.MaxConnections := 1024; + RunServer(8080); + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end + +end. diff --git a/samples/session_file_based/FileBasedSessionSample.dproj b/samples/session_file_based/FileBasedSessionSample.dproj new file mode 100644 index 00000000..4e9c4a3c --- /dev/null +++ b/samples/session_file_based/FileBasedSessionSample.dproj @@ -0,0 +1,899 @@ + + + {F9CBCE21-869A-478F-992C-88FCAC97BC8B} + 19.5 + VCL + FileBasedSessionSample.dpr + True + Debug + Win32 + 1 + Console + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + $(BDS)\bin\delphi_PROJECTICNS.icns + FileBasedSessionSample + ..\..\sources;..\..\lib\delphistompclient;..\..\lib\loggerpro;..\..\lib\dmustache;$(DCC_UnitSearchPath) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + None + 1040 + $(BDS)\bin\delphi_PROJECTICON.ico + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + 1033 + cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;JvDotNetCtrls;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;JvXPCtrls;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;FMXfrx17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;CloudService;dxPScxCommonRS17;FmxTeeUI;frxDB17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;JvRuntimeDesign;dxPScxVGridLnkRS17;JclDeveloperTools;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;MyFrameTestPackage;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;fs17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;DataBindingsVCL170;dxSkinOffice2010SilverRS17;vcldbx;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DataBindings;DBXOdbcDriver;IcsCommonDXE3Run;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;FMXTee;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;Jcl;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;Intraweb;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;fsDB17;inet;dorm_runtime_xe3;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;inetdbbde;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;MetropolisUILiveTile;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;vclribbon;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;CodeSiteExpressPkg;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;JvDocking;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;frx17;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;JclContainers;NxAddonsRun_dxe3;CPortLibDXE;JvSystem;dxorgcRS17;svnui;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;FMXfrxDB17;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;JclVcl;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;frxe17;svn;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;bdertl;VirtualTreesR;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage) + + + cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;dxPScxCommonRS17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;dxPScxVGridLnkRS17;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;dxSkinOffice2010SilverRS17;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DBXOdbcDriver;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;inet;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;NxAddonsRun_dxe3;JvSystem;dxorgcRS17;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + 3 + true + 1033 + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
WebModule1
+ TWebModule +
+ + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + Delphi.Personality.12 + + + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1040 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + + + + FileBasedSessionSample.dpr + + + Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver + Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server + + + + + + FileBasedSessionSample.exe + true + + + + + + 1 + + + 0 + + + + + classes + 64 + + + classes + 64 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + 1 + + + 0 + + + + + 1 + .framework + + + 1 + .framework + + + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/samples/session_file_based/WebModuleUnit1.dfm b/samples/session_file_based/WebModuleUnit1.dfm new file mode 100644 index 00000000..2c58d387 --- /dev/null +++ b/samples/session_file_based/WebModuleUnit1.dfm @@ -0,0 +1,11 @@ +object WebModule1: TWebModule1 + OnCreate = WebModuleCreate + Actions = < + item + Default = True + Name = 'DefaultHandler' + PathInfo = '/' + end> + Height = 230 + Width = 415 +end diff --git a/samples/session_file_based/WebModuleUnit1.pas b/samples/session_file_based/WebModuleUnit1.pas new file mode 100644 index 00000000..b7d8a556 --- /dev/null +++ b/samples/session_file_based/WebModuleUnit1.pas @@ -0,0 +1,44 @@ +unit WebModuleUnit1; + +interface + +uses + System.SysUtils, + System.Classes, + Web.HTTPApp, + MVCFramework; + +type + TWebModule1 = class(TWebModule) + procedure WebModuleCreate(Sender: TObject); + + private + MVC: TMVCEngine; + + public + { Public declarations } + end; + +var + WebModuleClass: TComponentClass = TWebModule1; + +implementation + +{$R *.dfm} + + +uses AppControllerU, MVCFramework.Commons; + +procedure TWebModule1.WebModuleCreate(Sender: TObject); +begin + MVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + Config[TMVCConfigKey.SessionTimeout] := '10'; // 10minutes + Config[TMVCConfigKey.DefaultContentType] := 'text/plain'; + Config[TMVCConfigKey.SessionType] := 'file'; + end); + MVC.AddController(TApp1MainController); +end; + +end. diff --git a/sources/MVCFramework.Session.pas b/sources/MVCFramework.Session.pas index 18cbc8f7..075afca7 100644 --- a/sources/MVCFramework.Session.pas +++ b/sources/MVCFramework.Session.pas @@ -32,15 +32,18 @@ uses System.SyncObjs, System.SysUtils, System.DateUtils, - System.Generics.Collections; + System.Generics.Collections, MVCFramework.Commons; const - DEFAULT_SESSION_INACTIVITY = 60; // in minutes type + EMVCSession = class(EMVCException) - TWebSession = class abstract + end; + + + TMVCWebSession = class abstract private FSessionId: string; FLastAccess: TDateTime; @@ -48,22 +51,25 @@ type protected function GetItems(const AKey: string): string; virtual; abstract; procedure SetItems(const AKey, AValue: string); virtual; abstract; + procedure SetLastAccess(Value: TDateTime); public constructor Create(const ASessionId: string; const ATimeout: UInt64); virtual; destructor Destroy; override; procedure MarkAsUsed; virtual; function ToString: string; override; function IsExpired: Boolean; virtual; - + function Keys: TArray; virtual; abstract; + class function TryFindSessionID(const ASessionID: String): Boolean; virtual; + class procedure TryDeleteSessionID(const ASessionID: String); virtual; property Items[const AKey: string]: string read GetItems write SetItems; default; property SessionId: string read FSessionId; property LastAccess: TDateTime read FLastAccess; property Timeout: UInt64 read FTimeout; end; - TWebSessionClass = class of TWebSession; + TMVCWebSessionClass = class of TMVCWebSession; - TWebSessionMemory = class(TWebSession) + TMVCWebSessionMemory = class(TMVCWebSession) private FData: TDictionary; protected @@ -72,37 +78,61 @@ type public constructor Create(const ASessionId: string; const ATimeout: UInt64); override; destructor Destroy; override; - function ToString: string; override; - property Data: TDictionary read FData; end; + + TMVCWebSessionFile = class(TMVCWebSessionMemory) + private + fSessionFolder: String; + protected + procedure StartLoading; + procedure EndLoading; + function GetFileName: String; overload; + class function GetFileName(const SessionFolder, SessionID: String): String; overload; + procedure LoadFromFile; + procedure SaveToFile; + procedure OnValueNotify(Sender: TObject; const Item: String; Action: TCollectionNotification); + public + constructor Create(const SessionID: string; const Timeout: UInt64); override; + destructor Destroy; override; + function Keys: System.TArray; override; + class function TryFindSessionID(const ASessionID: String): Boolean; override; + class procedure TryDeleteSessionID(const ASessionID: String); override; + end; + TMVCSessionFactory = class sealed private - FRegisteredSessionTypes: TDictionary; + FRegisteredSessionTypes: TDictionary; protected class var cInstance: TMVCSessionFactory; constructor Create; public destructor Destroy; override; - procedure RegisterSessionType(const AName: string; AWebSessionClass: TWebSessionClass); - function CreateNewByType(const AName, ASessionId: string; const ATimeout: UInt64): TWebSession; - + procedure RegisterSessionType(const AName: string; AWebSessionClass: TMVCWebSessionClass); + function CreateNewByType(const AName, ASessionId: string; const ATimeout: UInt64): TMVCWebSession; + function TryFindSessionID(const AName: string; const ASessionID: String): Boolean; + procedure TryDeleteSessionID(const AName: string; const ASessionID: String); class function GetInstance: TMVCSessionFactory; static; // class procedure DestroyInstance; static; end; -function GlobalSessionList: TObjectDictionary; +function GlobalSessionList: TObjectDictionary; implementation +uses + System.IOUtils, + System.Classes, + MVCFramework.Serializer.Commons; + var - GlSessionList: TObjectDictionary = nil; + GlSessionList: TObjectDictionary = nil; GlLastSessionListClear: TDateTime; GlCriticalSection: TCriticalSection; -function GlobalSessionList: TObjectDictionary; +function GlobalSessionList: TObjectDictionary; var S: string; begin @@ -111,7 +141,9 @@ begin GlCriticalSection.Enter; try if not Assigned(GlSessionList) then - GlSessionList := TObjectDictionary.Create([doOwnsValues]); + begin + GlSessionList := TObjectDictionary.Create([doOwnsValues]); + end; finally GlCriticalSection.Leave; end; @@ -122,7 +154,7 @@ begin TMonitor.Enter(GlSessionList); try for S in GlSessionList.Keys do - if TWebSession(GlSessionList.Items[S]).IsExpired then + if TMVCWebSession(GlSessionList.Items[S]).IsExpired then GlSessionList.Remove(S); GlLastSessionListClear := Now; finally @@ -135,19 +167,19 @@ end; { TWebSession } -constructor TWebSession.Create(const ASessionId: string; const ATimeout: UInt64); +constructor TMVCWebSession.Create(const ASessionId: string; const ATimeout: UInt64); begin inherited Create; FSessionId := ASessionId; FTimeout := ATimeout; end; -destructor TWebSession.Destroy; +destructor TMVCWebSession.Destroy; begin inherited Destroy; end; -function TWebSession.IsExpired: Boolean; +function TMVCWebSession.IsExpired: Boolean; begin if (FTimeout = 0) then Result := MinutesBetween(Now, LastAccess) > DEFAULT_SESSION_INACTIVITY @@ -155,31 +187,46 @@ begin Result := MinutesBetween(Now, LastAccess) > FTimeout; end; -procedure TWebSession.MarkAsUsed; +procedure TMVCWebSession.MarkAsUsed; begin FLastAccess := Now; end; -function TWebSession.ToString: string; +procedure TMVCWebSession.SetLastAccess(Value: TDateTime); +begin + FLastAccess := Value; +end; + +function TMVCWebSession.ToString: string; begin Result := ''; end; +class procedure TMVCWebSession.TryDeleteSessionID(const ASessionID: String); +begin + //do nothing +end; + +class function TMVCWebSession.TryFindSessionID(const ASessionID: String): Boolean; +begin + Result := False; +end; + { TWebSessionMemory } -constructor TWebSessionMemory.Create(const ASessionId: string; const ATimeout: UInt64); +constructor TMVCWebSessionMemory.Create(const ASessionId: string; const ATimeout: UInt64); begin inherited Create(ASessionId, ATimeout); FData := TDictionary.Create; end; -destructor TWebSessionMemory.Destroy; +destructor TMVCWebSessionMemory.Destroy; begin FData.Free; inherited Destroy; end; -function TWebSessionMemory.GetItems(const AKey: string): string; +function TMVCWebSessionMemory.GetItems(const AKey: string): string; begin TMonitor.Enter(Self); try @@ -190,7 +237,7 @@ begin end; end; -procedure TWebSessionMemory.SetItems(const AKey, AValue: string); +procedure TMVCWebSessionMemory.SetItems(const AKey, AValue: string); begin TMonitor.Enter(Self); try @@ -200,7 +247,7 @@ begin end; end; -function TWebSessionMemory.ToString: string; +function TMVCWebSessionMemory.ToString: string; var LKey: string; begin @@ -214,15 +261,15 @@ end; constructor TMVCSessionFactory.Create; begin inherited Create; - FRegisteredSessionTypes := TDictionary.Create; + FRegisteredSessionTypes := TDictionary.Create; end; -function TMVCSessionFactory.CreateNewByType(const AName, ASessionId: string; const ATimeout: UInt64): TWebSession; +function TMVCSessionFactory.CreateNewByType(const AName, ASessionId: string; const ATimeout: UInt64): TMVCWebSession; var - Clazz: TWebSessionClass; + Clazz: TMVCWebSessionClass; begin if not FRegisteredSessionTypes.TryGetValue(AName, Clazz) then - raise Exception.Create('Unknown application session type'); + raise EMVCSession.Create('Unknown application session type: ' + AName); Result := Clazz.Create(ASessionId, ATimeout); end; @@ -241,14 +288,164 @@ begin Result := cInstance; end; -procedure TMVCSessionFactory.RegisterSessionType(const AName: string; AWebSessionClass: TWebSessionClass); +procedure TMVCSessionFactory.RegisterSessionType(const AName: string; AWebSessionClass: TMVCWebSessionClass); begin FRegisteredSessionTypes.AddOrSetValue(AName, AWebSessionClass); end; +procedure TMVCSessionFactory.TryDeleteSessionID(const AName, ASessionID: String); +var + Clazz: TMVCWebSessionClass; +begin + if not FRegisteredSessionTypes.TryGetValue(AName, Clazz) then + raise EMVCSession.Create('Unknown application session type: ' + AName); + Clazz.TryDeleteSessionID(ASessionID); +end; + +function TMVCSessionFactory.TryFindSessionID(const AName: string; const ASessionID: String): Boolean; +var + Clazz: TMVCWebSessionClass; +begin + if not FRegisteredSessionTypes.TryGetValue(AName, Clazz) then + raise EMVCSession.Create('Unknown application session type: ' + AName); + Result := Clazz.TryFindSessionID(ASessionID); +end; + +{ TWebSessionMemoryController } + +constructor TMVCWebSessionFile.Create(const SessionID: string; const Timeout: UInt64); +begin + inherited Create(SessionID, Timeout); + Data.OnValueNotify := OnValueNotify; + fSessionFolder := TPath.Combine(AppPath, 'sessions'); + TDirectory.CreateDirectory(fSessionFolder); + LoadFromFile; + MarkAsUsed; + SaveToFile; +end; + +destructor TMVCWebSessionFile.Destroy; +begin + inherited; +end; + +procedure TMVCWebSessionFile.EndLoading; +begin + Data.OnValueNotify := OnValueNotify; +end; + +class function TMVCWebSessionFile.GetFileName(const SessionFolder, + SessionID: String): String; +begin + Result := TPath.Combine(SessionFolder, SessionId); +end; + +function TMVCWebSessionFile.GetFileName: String; +begin + Result := GetFileName(fSessionFolder, SessionId); +end; + +function TMVCWebSessionFile.Keys: System.TArray; +begin + Result := Data.Keys.ToArray; +end; + +procedure TMVCWebSessionFile.LoadFromFile; +var + lFileName: String; + lFile: TStreamReader; + lLine: string; + lPieces: TArray; +begin + lFileName := GetFileName; + if not TFile.Exists(lFileName) then + begin + Exit; + end; + //Log.Info('Loading session %s from %s', [SessionId, lFileName], 'file_session_events'); + lFile := TFile.OpenText(lFileName); + try + StartLoading; + try + SetLastAccess(ISOTimeStampToDateTime(lFile.ReadLine)); + while not lFile.EndOfStream do + begin + lLine := lFile.ReadLine; + lPieces := lLine.Split(['=']); + Data.Add(lPieces[0], lPieces[1]); + end; + finally + EndLoading; + end; + finally + lFile.Free; + end; +end; + +procedure TMVCWebSessionFile.OnValueNotify(Sender: TObject; const Item: String; + Action: TCollectionNotification); +begin + if Action in [cnAdded, cnExtracted, cnRemoved] then + begin + //Log.Info('Saving session %s because item changed [%s]', [SessionId, Item], 'file_session_events'); + SaveToFile; + end; +end; + +procedure TMVCWebSessionFile.SaveToFile; +var + lFileName: String; + lPair: TPair; + lFile: TStreamWriter; +begin + MarkAsUsed; + lFileName := GetFileName; + lFile := TFile.CreateText(lFileName); + try + lFile.WriteLine(DateTimeToISOTimeStamp(LastAccess)); + for lPair in Data do + begin + lFile.WriteLine(String.Join('=', [lPair.Key, lPair.Value])); + end; + lFile.Close; + finally + lFile.Free; + end; +end; + +procedure TMVCWebSessionFile.StartLoading; +begin + Data.OnValueNotify := nil; +end; + +class procedure TMVCWebSessionFile.TryDeleteSessionID(const ASessionID: String); +var + lSessionFolder: string; +begin + inherited; + lSessionFolder := TPath.Combine(AppPath, 'sessions'); + if TFile.Exists(GetFileName(lSessionFolder, ASessionID)) then + begin + TFile.Delete(GetFileName(lSessionFolder, ASessionID)); + end; +end; + +class function TMVCWebSessionFile.TryFindSessionID( + const ASessionID: String): Boolean; +var + lSessionFolder: string; +begin + inherited; + lSessionFolder := TPath.Combine(AppPath, 'sessions'); + Result := TFile.Exists(GetFileName(lSessionFolder, ASessionID)); +end; + + initialization -TMVCSessionFactory.GetInstance.RegisterSessionType('memory', TWebSessionMemory); +TMVCSessionFactory.GetInstance.RegisterSessionType('memory', TMVCWebSessionMemory); +TMVCSessionFactory.GetInstance.RegisterSessionType('file', TMVCWebSessionFile); + GlCriticalSection := TCriticalSection.Create; finalization diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index 1abe66bd..da2a2c1f 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -505,8 +505,8 @@ type function IsValid: Boolean; procedure Clear; - procedure SaveToSession(const AWebSession: TWebSession); - function LoadFromSession(const AWebSession: TWebSession): Boolean; + procedure SaveToSession(const AWebSession: TMVCWebSession); + function LoadFromSession(const AWebSession: TMVCWebSession): Boolean; property UserName: string read FUserName write FUserName; property Roles: TList read FRoles; @@ -524,10 +524,10 @@ type FIsSessionStarted: Boolean; FSessionMustBeClose: Boolean; FLoggedUser: TUser; - FWebSession: TWebSession; + FWebSession: TMVCWebSession; FData: TMVCStringDictionary; fIntfObject: IInterface; - function GetWebSession: TWebSession; + function GetWebSession: TMVCWebSession; function GetLoggedUser: TUser; function GetParamsTable: TMVCRequestParamsTable; procedure SetParamsTable(const AValue: TMVCRequestParamsTable); @@ -540,14 +540,14 @@ type procedure BindToSession(const ASessionId: string); function SendSessionCookie(const AContext: TWebContext): string; function AddSessionToTheSessionList(const ASessionType, ASessionId: string; - const ASessionTimeout: Integer): TWebSession; + const ASessionTimeout: Integer): TMVCWebSession; function GetData: TMVCStringDictionary; public constructor Create(const ARequest: TWebRequest; const AResponse: TWebResponse; const AConfig: TMVCConfig; const ASerializers: TDictionary); destructor Destroy; override; - procedure SessionStart; virtual; + procedure SessionStart(const SessionType: String); virtual; procedure SessionStop(const ARaiseExceptionIfExpired: Boolean = True); virtual; function SessionStarted: Boolean; @@ -559,7 +559,7 @@ type property LoggedUser: TUser read GetLoggedUser; property Request: TMVCWebRequest read FRequest; property Response: TMVCWebResponse read FResponse; - property Session: TWebSession read GetWebSession; + property Session: TMVCWebSession read GetWebSession; property Config: TMVCConfig read FConfig; property Data: TMVCStringDictionary read GetData; property CustomIntfObject: IInterface read GetIntfObject write SetIntfObject; @@ -776,7 +776,7 @@ type private FViewModel: TMVCViewDataObject; FViewDataSets: TMVCViewDataSet; - function GetSession: TWebSession; + function GetSession: TMVCWebSession; function GetViewData(const aModelName: string): TObject; function GetViewDataset(const aDataSetName: string): TDataSet; procedure SetViewData(const aModelName: string; const Value: TObject); @@ -812,7 +812,7 @@ type /// procedure LoadViewFragment(const AViewFragment: string); - function SessionAs: T; + function SessionAs: T; procedure RaiseSessionExpired; virtual; // Avoiding mid-air collisions - support @@ -823,7 +823,7 @@ type // Properties property Context: TWebContext read GetContext write FContext; - property Session: TWebSession read GetSession; + property Session: TMVCWebSession read GetSession; property ContentType: string read GetContentType write SetContentType; property StatusCode: Integer read GetStatusCode write SetStatusCode; procedure PushObjectToView(const aModelName: string; const AModel: TObject); @@ -985,7 +985,7 @@ type const AResponse: TWebResponse): Boolean; virtual; public class function GetCurrentSession(const ASessionId: string; - const ARaiseExceptionIfExpired: Boolean = True): TWebSession; static; + const ARaiseExceptionIfExpired: Boolean = True): TMVCWebSession; static; class function ExtractSessionIdFromWebRequest(const AWebRequest: TWebRequest): string; static; class function SendSessionCookie(const AContext: TWebContext): string; overload; static; class function SendSessionCookie(const AContext: TWebContext; const ASessionId: string): string; @@ -996,7 +996,7 @@ type const ACustomLogger: ILogWriter = nil); reintroduce; destructor Destroy; override; - function GetSessionBySessionId(const ASessionId: string): TWebSession; + function GetSessionBySessionId(const ASessionId: string): TMVCWebSession; { webcontext events} procedure OnWebContextCreate(const WebContextCreateEvent: TWebContextCreateEvent); @@ -1916,7 +1916,7 @@ begin Result := (not UserName.IsEmpty) and (LoggedSince > 0); end; -function TUser.LoadFromSession(const AWebSession: TWebSession): Boolean; +function TUser.LoadFromSession(const AWebSession: TMVCWebSession): Boolean; var SerObj: string; Pieces: TArray; @@ -1940,7 +1940,7 @@ begin end; end; -procedure TUser.SaveToSession(const AWebSession: TWebSession); +procedure TUser.SaveToSession(const AWebSession: TMVCWebSession); var LRoles: string; begin @@ -1968,9 +1968,9 @@ end; { TWebContext } function TWebContext.AddSessionToTheSessionList(const ASessionType, ASessionId: string; - const ASessionTimeout: Integer): TWebSession; + const ASessionTimeout: Integer): TMVCWebSession; var - Session: TWebSession; + Session: TMVCWebSession; begin if (Trim(ASessionType) = EmptyStr) then raise EMVCException.Create('Empty Session Type'); @@ -2142,16 +2142,35 @@ begin Result := FRequest.ParamsTable; end; -function TWebContext.GetWebSession: TWebSession; +function TWebContext.GetWebSession: TMVCWebSession; +var + lSessionIDFromRequest: string; + lSessionType: String; begin if not Assigned(FWebSession) then begin - FWebSession := TMVCEngine.GetCurrentSession( - TMVCEngine.ExtractSessionIdFromWebRequest(FRequest.RawWebRequest), False); + lSessionIDFromRequest := TMVCEngine.ExtractSessionIdFromWebRequest(FRequest.RawWebRequest); + FWebSession := TMVCEngine.GetCurrentSession(lSessionIDFromRequest, False); if not Assigned(FWebSession) then - SessionStart + begin + lSessionType := Config[TMVCConfigKey.SessionType]; + if not TMVCSessionFactory.GetInstance.TryFindSessionID(lSessionType, lSessionIDFromRequest) then + begin + SessionStart(lSessionType); + end + else + begin + FWebSession := AddSessionToTheSessionList( + lSessionType, + lSessionIDFromRequest, + StrToInt(Config[TMVCConfigKey.SessionTimeout])); + TMVCEngine.SendSessionCookie(Self, FWebSession.SessionId); + end; + end else + begin TMVCEngine.SendSessionCookie(Self, FWebSession.SessionId); + end; end; Result := FWebSession; Result.MarkAsUsed; @@ -2179,14 +2198,14 @@ begin Result := FSessionMustBeClose; end; -procedure TWebContext.SessionStart; +procedure TWebContext.SessionStart(const SessionType: String); var ID: string; begin if not Assigned(FWebSession) then begin ID := TMVCEngine.SendSessionCookie(Self); - FWebSession := AddSessionToTheSessionList(Config[TMVCConfigKey.SessionType], ID, + FWebSession := AddSessionToTheSessionList(SessionType, ID, StrToInt64(Config[TMVCConfigKey.SessionTimeout])); FIsSessionStarted := True; FSessionMustBeClose := False; @@ -2229,10 +2248,20 @@ begin begin raise EMVCSessionExpiredException.Create('Session not started'); end; + GlobalSessionList.Remove(SId); + if SId <> '' then begin FWebSession := nil; + try + TMVCSessionFactory.GetInstance.TryDeleteSessionID(Config[TMVCConfigKey.SessionType], SId); + except + on E: Exception do + begin + LogException(E, 'Cannot delete session file for sessionid: ' + SId); + end; + end; end; finally TMonitor.Exit(GlobalSessionList); @@ -3093,8 +3122,8 @@ begin end; end; -class function TMVCEngine.GetCurrentSession(const ASessionId: string; const ARaiseExceptionIfExpired: Boolean): TWebSession; -var lSessionList: TObjectDictionary; +class function TMVCEngine.GetCurrentSession(const ASessionId: string; const ARaiseExceptionIfExpired: Boolean): TMVCWebSession; +var lSessionList: TObjectDictionary; begin Result := nil; lSessionList := GlobalSessionList; @@ -3128,7 +3157,7 @@ begin end; end; -function TMVCEngine.GetSessionBySessionId(const ASessionId: string): TWebSession; +function TMVCEngine.GetSessionBySessionId(const ASessionId: string): TMVCWebSession; begin Result := TMVCEngine.GetCurrentSession(ASessionId, False); if Assigned(Result) then @@ -3340,10 +3369,14 @@ begin end; class function TMVCEngine.SendSessionCookie(const AContext: TWebContext): string; -var SId: string; +var + SId: string; begin - SId := StringReplace(StringReplace(StringReplace('DT' + GUIDToString(TGUID.NewGuid), '}', '', []), - '{', '', []), '-', '', [rfReplaceAll]); + SId := StringReplace(StringReplace(StringReplace( + 'DT' + GUIDToString(TGUID.NewGuid) + GUIDToString(TGUID.NewGuid), + '}', '', [rfReplaceAll]), + '{', '', [rfReplaceAll]), + '-', '', [rfReplaceAll]); Result := SendSessionCookie(AContext, SId); end; @@ -3621,7 +3654,7 @@ begin Result := Context.Request.GetHeader('If-Match'); end; -function TMVCController.GetSession: TWebSession; +function TMVCController.GetSession: TMVCWebSession; begin Result := GetContext.Session; end; From 927c58d29c0caa5c3d61b8ad3ef2c4bc5d39a5b8 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Sat, 12 Aug 2023 22:56:53 +0200 Subject: [PATCH 27/31] Removed duplicated packages for Delphi 11 Alexandria. Use d113 always. --- packages/d111/dmvcframeworkDT.dpk | 58 -- packages/d111/dmvcframeworkDT.dproj | 948 ------------------- packages/d111/dmvcframeworkRT.dpk | 120 --- packages/d111/dmvcframeworkRT.dproj | 979 ------------------- packages/d111/dmvcframework_group.groupproj | 72 -- packages/d112/dmvcframeworkDT.dpk | 58 -- packages/d112/dmvcframeworkDT.dproj | 948 ------------------- packages/d112/dmvcframeworkRT.dpk | 120 --- packages/d112/dmvcframeworkRT.dproj | 980 -------------------- packages/d112/dmvcframework_group.groupproj | 72 -- 10 files changed, 4355 deletions(-) delete mode 100644 packages/d111/dmvcframeworkDT.dpk delete mode 100644 packages/d111/dmvcframeworkDT.dproj delete mode 100644 packages/d111/dmvcframeworkRT.dpk delete mode 100644 packages/d111/dmvcframeworkRT.dproj delete mode 100644 packages/d111/dmvcframework_group.groupproj delete mode 100644 packages/d112/dmvcframeworkDT.dpk delete mode 100644 packages/d112/dmvcframeworkDT.dproj delete mode 100644 packages/d112/dmvcframeworkRT.dpk delete mode 100644 packages/d112/dmvcframeworkRT.dproj delete mode 100644 packages/d112/dmvcframework_group.groupproj diff --git a/packages/d111/dmvcframeworkDT.dpk b/packages/d111/dmvcframeworkDT.dpk deleted file mode 100644 index 12457b25..00000000 --- a/packages/d111/dmvcframeworkDT.dpk +++ /dev/null @@ -1,58 +0,0 @@ -package dmvcframeworkDT; - -{$R *.res} -{$R *.dres} -{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} -{$ALIGN 8} -{$ASSERTIONS ON} -{$BOOLEVAL OFF} -{$DEBUGINFO OFF} -{$EXTENDEDSYNTAX ON} -{$IMPORTEDDATA ON} -{$IOCHECKS ON} -{$LOCALSYMBOLS ON} -{$LONGSTRINGS ON} -{$OPENSTRINGS ON} -{$OPTIMIZATION OFF} -{$OVERFLOWCHECKS OFF} -{$RANGECHECKS OFF} -{$REFERENCEINFO ON} -{$SAFEDIVIDE OFF} -{$STACKFRAMES ON} -{$TYPEDADDRESS OFF} -{$VARSTRINGCHECKS ON} -{$WRITEABLECONST OFF} -{$MINENUMSIZE 1} -{$IMAGEBASE $400000} -{$DEFINE DEBUG} -{$ENDIF IMPLICITBUILDING} -{$DESCRIPTION 'DelphiMVCFramework 3.x - Design Time Support'} -{$LIBSUFFIX '111'} -{$IMPLICITBUILD ON} - -requires - rtl, - designide, - ExpertsCreators, - IndySystem, - IndyProtocols, - IndyCore, - dbrtl, - dmvcframeworkRT; - -contains - DMVC.Expert.CodeGen.NewControllerUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewControllerUnit.pas', - DMVC.Expert.CodeGen.NewDMVCProject in '..\..\ideexpert\DMVC.Expert.CodeGen.NewDMVCProject.pas', - DMVC.Expert.CodeGen.NewProject in '..\..\ideexpert\DMVC.Expert.CodeGen.NewProject.pas', - DMVC.Expert.CodeGen.NewUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewUnit.pas', - DMVC.Expert.CodeGen.NewWebModuleUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewWebModuleUnit.pas', - DMVC.Expert.CodeGen.SourceFile in '..\..\ideexpert\DMVC.Expert.CodeGen.SourceFile.pas', - DMVC.Expert.CodeGen.Templates in '..\..\ideexpert\DMVC.Expert.CodeGen.Templates.pas', - DMVC.Expert.Forms.NewProjectWizard in '..\..\ideexpert\DMVC.Expert.Forms.NewProjectWizard.pas' {frmDMVCNewProject}, - DMVC.Expert.Forms.NewUnitWizard in '..\..\ideexpert\DMVC.Expert.Forms.NewUnitWizard.pas' {frmDMVCNewUnit}, - DMVC.Expert.NewUnitWizardEx in '..\..\ideexpert\DMVC.Expert.NewUnitWizardEx.pas', - DMVC.Expert.ProjectWizardEx in '..\..\ideexpert\DMVC.Expert.ProjectWizardEx.pas', - DMVC.Expert.Registration in '..\..\ideexpert\DMVC.Expert.Registration.pas', - DMVC.Splash.Registration in '..\..\ideexpert\DMVC.Splash.Registration.pas'; - -end. diff --git a/packages/d111/dmvcframeworkDT.dproj b/packages/d111/dmvcframeworkDT.dproj deleted file mode 100644 index 4690f54f..00000000 --- a/packages/d111/dmvcframeworkDT.dproj +++ /dev/null @@ -1,948 +0,0 @@ - - - {84344511-1DC2-41BA-8689-9F36C1D475BE} - dmvcframeworkDT.dpk - 19.5 - None - True - Debug - Win32 - 1 - Package - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_1 - true - true - - - true - Base - true - - - true - Cfg_2 - true - true - - - .\$(Platform)\$(Config) - .\$(Platform)\$(Config) - false - false - false - false - false - true - true - System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) - All - dmvcframeworkDT - 1040 - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - DelphiMVCFramework IDE Expert - - - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - Debug - annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - Debug - annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - Debug - true - 1033 - rtl;IndySystem;IndyProtocols;IndyCore;dbrtl;dmvcframeworkRT;$(DCC_UsePackage) - ..\..\sources;$(DCC_UnitSearchPath) - DelphiMVCFramework 3.x - Design Time Support - 110 - - - rtl;IndySystem;IndyProtocols;IndyCore;dbrtl;$(DCC_UsePackage) - - - DEBUG;$(DCC_Define) - true - false - true - true - true - - - false - true - 1033 - false - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=Daniele Teti and the DMVCFramework Team;LegalTrademarks=DelphiMVCFramework;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - 111 - - - false - RELEASE;$(DCC_Define) - 0 - 0 - - - true - 1033 - - - - MainSource - - - - - - - - - - - - - - - - - -
frmDMVCNewProject
-
- -
frmDMVCNewUnit
-
- - - - - - ICON - DMVCNewProjectIcon - - - ICON - DMVCNewUnitIcon - - - BITMAP - SplashScreen - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - -
- - Delphi.Personality.12 - Package - - - - dmvcframeworkDT.dpk - - - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - - - - - true - - - - - true - - - - - - true - - - - - - - 1 - - - 0 - - - - - classes - 64 - - - classes - 64 - - - - - res\xml - 1 - - - res\xml - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\armeabi - 1 - - - library\lib\armeabi - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\mips - 1 - - - library\lib\mips - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\values-v21 - 1 - - - res\values-v21 - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-ldpi - 1 - - - res\drawable-ldpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-small - 1 - - - res\drawable-small - 1 - - - - - res\drawable-normal - 1 - - - res\drawable-normal - 1 - - - - - res\drawable-large - 1 - - - res\drawable-large - 1 - - - - - res\drawable-xlarge - 1 - - - res\drawable-xlarge - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - 1 - - - 1 - - - 0 - - - - - 1 - .framework - - - 1 - .framework - - - 1 - .framework - - - 0 - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .dll;.bpl - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .bpl - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - - - - - - - - - - - - - False - False - False - True - False - - - 12 - - - - -
diff --git a/packages/d111/dmvcframeworkRT.dpk b/packages/d111/dmvcframeworkRT.dpk deleted file mode 100644 index 3f9d64df..00000000 --- a/packages/d111/dmvcframeworkRT.dpk +++ /dev/null @@ -1,120 +0,0 @@ -package dmvcframeworkRT; - -{$R *.res} -{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} -{$ALIGN 8} -{$ASSERTIONS ON} -{$BOOLEVAL OFF} -{$DEBUGINFO OFF} -{$EXTENDEDSYNTAX ON} -{$IMPORTEDDATA ON} -{$IOCHECKS ON} -{$LOCALSYMBOLS ON} -{$LONGSTRINGS ON} -{$OPENSTRINGS ON} -{$OPTIMIZATION OFF} -{$OVERFLOWCHECKS OFF} -{$RANGECHECKS OFF} -{$REFERENCEINFO ON} -{$SAFEDIVIDE OFF} -{$STACKFRAMES ON} -{$TYPEDADDRESS OFF} -{$VARSTRINGCHECKS ON} -{$WRITEABLECONST OFF} -{$MINENUMSIZE 1} -{$IMAGEBASE $400000} -{$DEFINE DEBUG} -{$ENDIF IMPLICITBUILDING} -{$DESCRIPTION 'DMVCFramework - CopyRight (2010-2023) Daniele Teti and the DMVCFramework Team'} -{$LIBSUFFIX '111'} -{$RUNONLY} -{$IMPLICITBUILD ON} - -requires - rtl, - inet, - FireDAC, - IndyCore, - IndyProtocols, - FireDACIBDriver, - FireDACMySQLDriver, - loggerproRT, - FireDACPgDriver, - FireDACSqliteDriver, - SwagDoc; - -contains - Web.HTTPDImpl, - Web.ApacheConst, - Web.ApacheHTTP, - Web.Win.IsapiHTTP, - Web.HTTPDMethods, - MVCFramework in '..\..\sources\MVCFramework.pas', - MVCFramework.AsyncTask in '..\..\sources\MVCFramework.AsyncTask.pas', - MVCFramework.Middleware.Swagger in '..\..\sources\MVCFramework.Middleware.Swagger.pas', - MVCFramework.Middleware.Trace in '..\..\sources\MVCFramework.Middleware.Trace.pas', - MVCFramework.Middleware.ETag in '..\..\sources\MVCFramework.Middleware.ETag.pas', - MVCFramework.ActiveRecord in '..\..\sources\MVCFramework.ActiveRecord.pas', - MVCFramework.ActiveRecordController in '..\..\sources\MVCFramework.ActiveRecordController.pas', - MVCFramework.ApplicationSession in '..\..\sources\MVCFramework.ApplicationSession.pas', - MVCFramework.Cache in '..\..\sources\MVCFramework.Cache.pas', - MVCFramework.Commons in '..\..\sources\MVCFramework.Commons.pas', - MVCFramework.Console in '..\..\sources\MVCFramework.Console.pas', - MVCFramework.DataSet.Utils in '..\..\sources\MVCFramework.DataSet.Utils.pas', - MVCFramework.DuckTyping in '..\..\sources\MVCFramework.DuckTyping.pas', - MVCFramework.FireDAC.Utils in '..\..\sources\MVCFramework.FireDAC.Utils.pas', - MVCFramework.HMAC in '..\..\sources\MVCFramework.HMAC.pas', - MVCFramework.JSONRPC.Client in '..\..\sources\MVCFramework.JSONRPC.Client.pas', - MVCFramework.JSONRPC in '..\..\sources\MVCFramework.JSONRPC.pas', - MVCFramework.JWT in '..\..\sources\MVCFramework.JWT.pas', - MVCFramework.Logger in '..\..\sources\MVCFramework.Logger.pas', - MVCFramework.Middleware.Analytics in '..\..\sources\MVCFramework.Middleware.Analytics.pas', - MVCFramework.Middleware.Authentication in '..\..\sources\MVCFramework.Middleware.Authentication.pas', - MVCFramework.Middleware.Authentication.RoleBasedAuthHandler in '..\..\sources\MVCFramework.Middleware.Authentication.RoleBasedAuthHandler.pas', - MVCFramework.Middleware.Compression in '..\..\sources\MVCFramework.Middleware.Compression.pas', - MVCFramework.Middleware.CORS in '..\..\sources\MVCFramework.Middleware.CORS.pas', - MVCFramework.Middleware.JWT in '..\..\sources\MVCFramework.Middleware.JWT.pas', - MVCFramework.Middleware.SecurityHeaders in '..\..\sources\MVCFramework.Middleware.SecurityHeaders.pas', - MVCFramework.MultiMap in '..\..\sources\MVCFramework.MultiMap.pas', - MVCFramework.Patches in '..\..\sources\MVCFramework.Patches.pas', - MVCFramework.RESTAdapter in '..\..\sources\MVCFramework.RESTAdapter.pas', - MVCFramework.Router in '..\..\sources\MVCFramework.Router.pas', - MVCFramework.RQL.AST2FirebirdSQL in '..\..\sources\MVCFramework.RQL.AST2FirebirdSQL.pas', - MVCFramework.RQL.AST2InterbaseSQL in '..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas', - MVCFramework.RQL.AST2MySQL in '..\..\sources\MVCFramework.RQL.AST2MySQL.pas', - MVCFramework.RQL.AST2PostgreSQL in '..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas', - MVCFramework.RQL.AST2SQLite in '..\..\sources\MVCFramework.RQL.AST2SQLite.pas', - MVCFramework.RQL.Parser in '..\..\sources\MVCFramework.RQL.Parser.pas', - MVCFramework.Rtti.Utils in '..\..\sources\MVCFramework.Rtti.Utils.pas', - MVCFramework.Serializer.Abstract in '..\..\sources\MVCFramework.Serializer.Abstract.pas', - MVCFramework.Serializer.Commons in '..\..\sources\MVCFramework.Serializer.Commons.pas', - MVCFramework.Serializer.Defaults in '..\..\sources\MVCFramework.Serializer.Defaults.pas', - MVCFramework.Serializer.Intf in '..\..\sources\MVCFramework.Serializer.Intf.pas', - MVCFramework.Serializer.JsonDataObjects.CustomTypes in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas', - MVCFramework.Serializer.JsonDataObjects in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas', - MVCFramework.Session in '..\..\sources\MVCFramework.Session.pas', - MVCFramework.SysControllers in '..\..\sources\MVCFramework.SysControllers.pas', - MVCFramework.SystemJSONUtils in '..\..\sources\MVCFramework.SystemJSONUtils.pas', - MVCFramework.View.Cache in '..\..\sources\MVCFramework.View.Cache.pas', - MVCFramework.Controllers.Register in '..\..\sources\MVCFramework.Controllers.Register.pas', - MVCFramework.SQLGenerators.Firebird in '..\..\sources\MVCFramework.SQLGenerators.Firebird.pas', - MVCFramework.SQLGenerators.Interbase in '..\..\sources\MVCFramework.SQLGenerators.Interbase.pas', - MVCFramework.SQLGenerators.MySQL in '..\..\sources\MVCFramework.SQLGenerators.MySQL.pas', - MVCFramework.SQLGenerators.PostgreSQL in '..\..\sources\MVCFramework.SQLGenerators.PostgreSQL.pas', - MVCFramework.SQLGenerators.Sqlite in '..\..\sources\MVCFramework.SQLGenerators.Sqlite.pas', - MVCFramework.Swagger.Commons in '..\..\sources\MVCFramework.Swagger.Commons.pas', - MVCFramework.Nullables in '..\..\sources\MVCFramework.Nullables.pas', - MVCFramework.Serializer.HTML in '..\..\sources\MVCFramework.Serializer.HTML.pas', - MVCFramework.LRUCache in '..\..\sources\MVCFramework.LRUCache.pas', - MVCFramework.RESTClient.Commons in '..\..\sources\MVCFramework.RESTClient.Commons.pas', - MVCFramework.RESTClient.Indy in '..\..\sources\MVCFramework.RESTClient.Indy.pas', - MVCFramework.RESTClient.Intf in '..\..\sources\MVCFramework.RESTClient.Intf.pas', - MVCFramework.RESTClient in '..\..\sources\MVCFramework.RESTClient.pas', - MVCFramework.Utils in '..\..\sources\MVCFramework.Utils.pas', - JsonDataObjects in '..\..\sources\JsonDataObjects.pas'; - -end. - - - - diff --git a/packages/d111/dmvcframeworkRT.dproj b/packages/d111/dmvcframeworkRT.dproj deleted file mode 100644 index 78f3dec3..00000000 --- a/packages/d111/dmvcframeworkRT.dproj +++ /dev/null @@ -1,979 +0,0 @@ - - - {96D17257-AF74-48CB-9893-7BCCB56A069D} - dmvcframeworkRT.dpk - 19.5 - None - True - Debug - Win32 - 1 - Package - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_1 - true - true - - - true - Base - true - - - .\$(Platform)\$(Config) - .\$(Platform)\$(Config) - false - false - false - false - false - true - true - System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) - All - dmvcframeworkRT - true - 1040 - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - DMVCFramework - CopyRight (2010-2020) Daniele Teti and the DMVCFramework Team - - - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - Debug - annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - Debug - annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - Debug - true - 1033 - DMVCFramework - CopyRight (2010-2021) Daniele Teti and the DMVCFramework Team - rtl;dbrtl;IndySystem;IndyProtocols;IndyCore;dmvcframeworkDT;$(DCC_UsePackage) - 110 - - - rtl;dbrtl;IndySystem;IndyProtocols;IndyCore;$(DCC_UsePackage) - - - DEBUG;$(DCC_Define) - true - false - true - true - true - - - true - 1033 - 3 - true - false - true - CompanyName=Daniele Teti and the DMVCFramework Team;FileDescription=DelphiMVCFramework 3.2.2-nitrogen;FileVersion=3.2.2.0;InternalName=DelphiMVCFramework 3.2.2-nitrogen;LegalCopyright=Daniele Teti and the DMVCFramework Team - Apache License 2;LegalTrademarks=DelphiMVCFramework;OriginalFilename=$(MSBuildProjectName);ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=DelphiMVCFramework;ProductVersion=3.2.2;Comments= - 3 - 2 - 2 - 111 - - - false - RELEASE;$(DCC_Define) - 0 - 0 - - - - MainSource - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - - - - Delphi.Personality.12 - Package - - - - dmvcframeworkRT.dpk - - - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - - - - true - - - - - true - - - - - - true - - - - - - - 1 - - - 0 - - - - - classes - 64 - - - classes - 64 - - - - - res\xml - 1 - - - res\xml - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\armeabi - 1 - - - library\lib\armeabi - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\mips - 1 - - - library\lib\mips - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\values-v21 - 1 - - - res\values-v21 - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-ldpi - 1 - - - res\drawable-ldpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-small - 1 - - - res\drawable-small - 1 - - - - - res\drawable-normal - 1 - - - res\drawable-normal - 1 - - - - - res\drawable-large - 1 - - - res\drawable-large - 1 - - - - - res\drawable-xlarge - 1 - - - res\drawable-xlarge - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - 1 - - - 1 - - - 0 - - - - - 1 - .framework - - - 1 - .framework - - - 1 - .framework - - - 0 - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .dll;.bpl - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .bpl - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - - - - - - - - - - - - - False - False - False - True - False - - - 12 - - - - - diff --git a/packages/d111/dmvcframework_group.groupproj b/packages/d111/dmvcframework_group.groupproj deleted file mode 100644 index 7349df03..00000000 --- a/packages/d111/dmvcframework_group.groupproj +++ /dev/null @@ -1,72 +0,0 @@ - - - {EA879EE4-1245-4456-AED9-57FDF63577E6} - - - - - - - - - - ..\..\lib\loggerpro\packages\d111\loggerproRT.dproj - - - dmvcframeworkRT.dproj - - - - Default.Personality.12 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/d112/dmvcframeworkDT.dpk b/packages/d112/dmvcframeworkDT.dpk deleted file mode 100644 index 6fd2dc2e..00000000 --- a/packages/d112/dmvcframeworkDT.dpk +++ /dev/null @@ -1,58 +0,0 @@ -package dmvcframeworkDT; - -{$R *.res} -{$R *.dres} -{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} -{$ALIGN 8} -{$ASSERTIONS ON} -{$BOOLEVAL OFF} -{$DEBUGINFO OFF} -{$EXTENDEDSYNTAX ON} -{$IMPORTEDDATA ON} -{$IOCHECKS ON} -{$LOCALSYMBOLS ON} -{$LONGSTRINGS ON} -{$OPENSTRINGS ON} -{$OPTIMIZATION OFF} -{$OVERFLOWCHECKS OFF} -{$RANGECHECKS OFF} -{$REFERENCEINFO ON} -{$SAFEDIVIDE OFF} -{$STACKFRAMES ON} -{$TYPEDADDRESS OFF} -{$VARSTRINGCHECKS ON} -{$WRITEABLECONST OFF} -{$MINENUMSIZE 1} -{$IMAGEBASE $400000} -{$DEFINE DEBUG} -{$ENDIF IMPLICITBUILDING} -{$DESCRIPTION 'DelphiMVCFramework 3.x - Design Time Support'} -{$LIBSUFFIX '112'} -{$IMPLICITBUILD ON} - -requires - rtl, - designide, - ExpertsCreators, - IndySystem, - IndyProtocols, - IndyCore, - dbrtl, - dmvcframeworkRT; - -contains - DMVC.Expert.CodeGen.NewControllerUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewControllerUnit.pas', - DMVC.Expert.CodeGen.NewDMVCProject in '..\..\ideexpert\DMVC.Expert.CodeGen.NewDMVCProject.pas', - DMVC.Expert.CodeGen.NewProject in '..\..\ideexpert\DMVC.Expert.CodeGen.NewProject.pas', - DMVC.Expert.CodeGen.NewUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewUnit.pas', - DMVC.Expert.CodeGen.NewWebModuleUnit in '..\..\ideexpert\DMVC.Expert.CodeGen.NewWebModuleUnit.pas', - DMVC.Expert.CodeGen.SourceFile in '..\..\ideexpert\DMVC.Expert.CodeGen.SourceFile.pas', - DMVC.Expert.CodeGen.Templates in '..\..\ideexpert\DMVC.Expert.CodeGen.Templates.pas', - DMVC.Expert.Forms.NewProjectWizard in '..\..\ideexpert\DMVC.Expert.Forms.NewProjectWizard.pas' {frmDMVCNewProject}, - DMVC.Expert.Forms.NewUnitWizard in '..\..\ideexpert\DMVC.Expert.Forms.NewUnitWizard.pas' {frmDMVCNewUnit}, - DMVC.Expert.NewUnitWizardEx in '..\..\ideexpert\DMVC.Expert.NewUnitWizardEx.pas', - DMVC.Expert.ProjectWizardEx in '..\..\ideexpert\DMVC.Expert.ProjectWizardEx.pas', - DMVC.Expert.Registration in '..\..\ideexpert\DMVC.Expert.Registration.pas', - DMVC.Splash.Registration in '..\..\ideexpert\DMVC.Splash.Registration.pas'; - -end. diff --git a/packages/d112/dmvcframeworkDT.dproj b/packages/d112/dmvcframeworkDT.dproj deleted file mode 100644 index aa8c1caf..00000000 --- a/packages/d112/dmvcframeworkDT.dproj +++ /dev/null @@ -1,948 +0,0 @@ - - - {84344511-1DC2-41BA-8689-9F36C1D475BE} - dmvcframeworkDT.dpk - 19.5 - None - True - Debug - Win32 - 1 - Package - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_1 - true - true - - - true - Base - true - - - true - Cfg_2 - true - true - - - .\$(Platform)\$(Config) - .\$(Platform)\$(Config) - false - false - false - false - false - true - true - System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) - All - dmvcframeworkDT - 1040 - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - DelphiMVCFramework IDE Expert - - - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - Debug - annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - Debug - annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - Debug - true - 1033 - rtl;IndySystem;IndyProtocols;IndyCore;dbrtl;dmvcframeworkRT;$(DCC_UsePackage) - ..\..\sources;$(DCC_UnitSearchPath) - DelphiMVCFramework 3.x - Design Time Support - 110 - - - rtl;IndySystem;IndyProtocols;IndyCore;dbrtl;$(DCC_UsePackage) - - - DEBUG;$(DCC_Define) - true - false - true - true - true - - - false - true - 1033 - false - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=Daniele Teti and the DMVCFramework Team;LegalTrademarks=DelphiMVCFramework;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - 112 - - - false - RELEASE;$(DCC_Define) - 0 - 0 - - - true - 1033 - - - - MainSource - - - - - - - - - - - - - - - - - -
frmDMVCNewProject
-
- -
frmDMVCNewUnit
-
- - - - - - ICON - DMVCNewProjectIcon - - - ICON - DMVCNewUnitIcon - - - BITMAP - SplashScreen - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - -
- - Delphi.Personality.12 - Package - - - - dmvcframeworkDT.dpk - - - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - - - - true - - - - - - true - - - - - - true - - - - - - - 1 - - - 0 - - - - - classes - 64 - - - classes - 64 - - - - - res\xml - 1 - - - res\xml - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\armeabi - 1 - - - library\lib\armeabi - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\mips - 1 - - - library\lib\mips - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\values-v21 - 1 - - - res\values-v21 - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-ldpi - 1 - - - res\drawable-ldpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-small - 1 - - - res\drawable-small - 1 - - - - - res\drawable-normal - 1 - - - res\drawable-normal - 1 - - - - - res\drawable-large - 1 - - - res\drawable-large - 1 - - - - - res\drawable-xlarge - 1 - - - res\drawable-xlarge - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - 1 - - - 1 - - - 0 - - - - - 1 - .framework - - - 1 - .framework - - - 1 - .framework - - - 0 - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .dll;.bpl - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .bpl - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - - - - - - - - - - - - - False - False - False - True - False - - - 12 - - - - -
diff --git a/packages/d112/dmvcframeworkRT.dpk b/packages/d112/dmvcframeworkRT.dpk deleted file mode 100644 index 49a16eef..00000000 --- a/packages/d112/dmvcframeworkRT.dpk +++ /dev/null @@ -1,120 +0,0 @@ -package dmvcframeworkRT; - -{$R *.res} -{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} -{$ALIGN 8} -{$ASSERTIONS ON} -{$BOOLEVAL OFF} -{$DEBUGINFO OFF} -{$EXTENDEDSYNTAX ON} -{$IMPORTEDDATA ON} -{$IOCHECKS ON} -{$LOCALSYMBOLS ON} -{$LONGSTRINGS ON} -{$OPENSTRINGS ON} -{$OPTIMIZATION OFF} -{$OVERFLOWCHECKS OFF} -{$RANGECHECKS OFF} -{$REFERENCEINFO ON} -{$SAFEDIVIDE OFF} -{$STACKFRAMES ON} -{$TYPEDADDRESS OFF} -{$VARSTRINGCHECKS ON} -{$WRITEABLECONST OFF} -{$MINENUMSIZE 1} -{$IMAGEBASE $400000} -{$DEFINE DEBUG} -{$ENDIF IMPLICITBUILDING} -{$DESCRIPTION 'DMVCFramework - CopyRight (2010-2023) Daniele Teti and the DMVCFramework Team'} -{$LIBSUFFIX '112'} -{$RUNONLY} -{$IMPLICITBUILD ON} - -requires - rtl, - inet, - FireDAC, - IndyCore, - IndyProtocols, - FireDACIBDriver, - FireDACMySQLDriver, - loggerproRT, - FireDACPgDriver, - FireDACSqliteDriver, - SwagDoc; - -contains - Web.HTTPDImpl, - Web.ApacheConst, - Web.ApacheHTTP, - Web.Win.IsapiHTTP, - Web.HTTPDMethods, - MVCFramework in '..\..\sources\MVCFramework.pas', - MVCFramework.AsyncTask in '..\..\sources\MVCFramework.AsyncTask.pas', - MVCFramework.Middleware.Swagger in '..\..\sources\MVCFramework.Middleware.Swagger.pas', - MVCFramework.Middleware.Trace in '..\..\sources\MVCFramework.Middleware.Trace.pas', - MVCFramework.Middleware.ETag in '..\..\sources\MVCFramework.Middleware.ETag.pas', - MVCFramework.ActiveRecord in '..\..\sources\MVCFramework.ActiveRecord.pas', - MVCFramework.ActiveRecordController in '..\..\sources\MVCFramework.ActiveRecordController.pas', - MVCFramework.ApplicationSession in '..\..\sources\MVCFramework.ApplicationSession.pas', - MVCFramework.Cache in '..\..\sources\MVCFramework.Cache.pas', - MVCFramework.Commons in '..\..\sources\MVCFramework.Commons.pas', - MVCFramework.Console in '..\..\sources\MVCFramework.Console.pas', - MVCFramework.DataSet.Utils in '..\..\sources\MVCFramework.DataSet.Utils.pas', - MVCFramework.DuckTyping in '..\..\sources\MVCFramework.DuckTyping.pas', - MVCFramework.FireDAC.Utils in '..\..\sources\MVCFramework.FireDAC.Utils.pas', - MVCFramework.HMAC in '..\..\sources\MVCFramework.HMAC.pas', - MVCFramework.JSONRPC.Client in '..\..\sources\MVCFramework.JSONRPC.Client.pas', - MVCFramework.JSONRPC in '..\..\sources\MVCFramework.JSONRPC.pas', - MVCFramework.JWT in '..\..\sources\MVCFramework.JWT.pas', - MVCFramework.Logger in '..\..\sources\MVCFramework.Logger.pas', - MVCFramework.Middleware.Analytics in '..\..\sources\MVCFramework.Middleware.Analytics.pas', - MVCFramework.Middleware.Authentication in '..\..\sources\MVCFramework.Middleware.Authentication.pas', - MVCFramework.Middleware.Authentication.RoleBasedAuthHandler in '..\..\sources\MVCFramework.Middleware.Authentication.RoleBasedAuthHandler.pas', - MVCFramework.Middleware.Compression in '..\..\sources\MVCFramework.Middleware.Compression.pas', - MVCFramework.Middleware.CORS in '..\..\sources\MVCFramework.Middleware.CORS.pas', - MVCFramework.Middleware.JWT in '..\..\sources\MVCFramework.Middleware.JWT.pas', - MVCFramework.Middleware.SecurityHeaders in '..\..\sources\MVCFramework.Middleware.SecurityHeaders.pas', - MVCFramework.MultiMap in '..\..\sources\MVCFramework.MultiMap.pas', - MVCFramework.Patches in '..\..\sources\MVCFramework.Patches.pas', - MVCFramework.RESTAdapter in '..\..\sources\MVCFramework.RESTAdapter.pas', - MVCFramework.Router in '..\..\sources\MVCFramework.Router.pas', - MVCFramework.RQL.AST2FirebirdSQL in '..\..\sources\MVCFramework.RQL.AST2FirebirdSQL.pas', - MVCFramework.RQL.AST2InterbaseSQL in '..\..\sources\MVCFramework.RQL.AST2InterbaseSQL.pas', - MVCFramework.RQL.AST2MySQL in '..\..\sources\MVCFramework.RQL.AST2MySQL.pas', - MVCFramework.RQL.AST2PostgreSQL in '..\..\sources\MVCFramework.RQL.AST2PostgreSQL.pas', - MVCFramework.RQL.AST2SQLite in '..\..\sources\MVCFramework.RQL.AST2SQLite.pas', - MVCFramework.RQL.Parser in '..\..\sources\MVCFramework.RQL.Parser.pas', - MVCFramework.Rtti.Utils in '..\..\sources\MVCFramework.Rtti.Utils.pas', - MVCFramework.Serializer.Abstract in '..\..\sources\MVCFramework.Serializer.Abstract.pas', - MVCFramework.Serializer.Commons in '..\..\sources\MVCFramework.Serializer.Commons.pas', - MVCFramework.Serializer.Defaults in '..\..\sources\MVCFramework.Serializer.Defaults.pas', - MVCFramework.Serializer.Intf in '..\..\sources\MVCFramework.Serializer.Intf.pas', - MVCFramework.Serializer.JsonDataObjects.CustomTypes in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas', - MVCFramework.Serializer.JsonDataObjects in '..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas', - MVCFramework.Session in '..\..\sources\MVCFramework.Session.pas', - MVCFramework.SysControllers in '..\..\sources\MVCFramework.SysControllers.pas', - MVCFramework.SystemJSONUtils in '..\..\sources\MVCFramework.SystemJSONUtils.pas', - MVCFramework.View.Cache in '..\..\sources\MVCFramework.View.Cache.pas', - MVCFramework.Controllers.Register in '..\..\sources\MVCFramework.Controllers.Register.pas', - MVCFramework.SQLGenerators.Firebird in '..\..\sources\MVCFramework.SQLGenerators.Firebird.pas', - MVCFramework.SQLGenerators.Interbase in '..\..\sources\MVCFramework.SQLGenerators.Interbase.pas', - MVCFramework.SQLGenerators.MySQL in '..\..\sources\MVCFramework.SQLGenerators.MySQL.pas', - MVCFramework.SQLGenerators.PostgreSQL in '..\..\sources\MVCFramework.SQLGenerators.PostgreSQL.pas', - MVCFramework.SQLGenerators.Sqlite in '..\..\sources\MVCFramework.SQLGenerators.Sqlite.pas', - MVCFramework.Swagger.Commons in '..\..\sources\MVCFramework.Swagger.Commons.pas', - MVCFramework.Nullables in '..\..\sources\MVCFramework.Nullables.pas', - MVCFramework.Serializer.HTML in '..\..\sources\MVCFramework.Serializer.HTML.pas', - MVCFramework.LRUCache in '..\..\sources\MVCFramework.LRUCache.pas', - MVCFramework.RESTClient.Commons in '..\..\sources\MVCFramework.RESTClient.Commons.pas', - MVCFramework.RESTClient.Indy in '..\..\sources\MVCFramework.RESTClient.Indy.pas', - MVCFramework.RESTClient.Intf in '..\..\sources\MVCFramework.RESTClient.Intf.pas', - MVCFramework.RESTClient in '..\..\sources\MVCFramework.RESTClient.pas', - MVCFramework.Utils in '..\..\sources\MVCFramework.Utils.pas', - JsonDataObjects in '..\..\sources\JsonDataObjects.pas'; - -end. - - - - diff --git a/packages/d112/dmvcframeworkRT.dproj b/packages/d112/dmvcframeworkRT.dproj deleted file mode 100644 index 835fb310..00000000 --- a/packages/d112/dmvcframeworkRT.dproj +++ /dev/null @@ -1,980 +0,0 @@ - - - {96D17257-AF74-48CB-9893-7BCCB56A069D} - dmvcframeworkRT.dpk - 19.5 - None - True - Debug - Win32 - 1 - Package - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_1 - true - true - - - true - Base - true - - - .\$(Platform)\$(Config) - .\$(Platform)\$(Config) - false - false - false - false - false - true - true - System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) - All - dmvcframeworkRT - true - 1040 - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - DMVCFramework - CopyRight (2010-2020) Daniele Teti and the DMVCFramework Team - - - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - Debug - annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= - Debug - annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - Debug - true - 1033 - DMVCFramework - CopyRight (2010-2021) Daniele Teti and the DMVCFramework Team - rtl;dbrtl;IndySystem;IndyProtocols;IndyCore;dmvcframeworkDT;$(DCC_UsePackage) - 110 - - - rtl;dbrtl;IndySystem;IndyProtocols;IndyCore;$(DCC_UsePackage) - - - DEBUG;$(DCC_Define) - true - false - true - true - true - - - true - 1033 - 3 - true - false - true - CompanyName=Daniele Teti and the DMVCFramework Team;FileDescription=DelphiMVCFramework 3.2.2-nitrogen;FileVersion=3.2.2.0;InternalName=DelphiMVCFramework 3.2.2-nitrogen;LegalCopyright=Daniele Teti and the DMVCFramework Team - Apache License 2;LegalTrademarks=DelphiMVCFramework;OriginalFilename=$(MSBuildProjectName);ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=DelphiMVCFramework;ProductVersion=3.2.2;Comments= - 3 - 2 - 2 - 112 - DMVCFramework - CopyRight (2010-2022) Daniele Teti and the DMVCFramework Team - - - false - RELEASE;$(DCC_Define) - 0 - 0 - - - - MainSource - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - - - - Delphi.Personality.12 - Package - - - - dmvcframeworkRT.dpk - - - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - - - - true - - - - - true - - - - - - true - - - - - - - dmvcframeworkRT.bpl - true - - - - - 1 - - - 0 - - - - - classes - 64 - - - classes - 64 - - - - - res\xml - 1 - - - res\xml - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\armeabi - 1 - - - library\lib\armeabi - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\mips - 1 - - - library\lib\mips - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\values-v21 - 1 - - - res\values-v21 - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-ldpi - 1 - - - res\drawable-ldpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-small - 1 - - - res\drawable-small - 1 - - - - - res\drawable-normal - 1 - - - res\drawable-normal - 1 - - - - - res\drawable-large - 1 - - - res\drawable-large - 1 - - - - - res\drawable-xlarge - 1 - - - res\drawable-xlarge - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - 1 - - - 1 - - - 0 - - - - - 1 - .framework - - - 1 - .framework - - - 1 - .framework - - - 0 - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .dll;.bpl - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .bpl - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - - - - - - - - - - - - - False - False - False - True - False - - - 12 - - - - - diff --git a/packages/d112/dmvcframework_group.groupproj b/packages/d112/dmvcframework_group.groupproj deleted file mode 100644 index 7349df03..00000000 --- a/packages/d112/dmvcframework_group.groupproj +++ /dev/null @@ -1,72 +0,0 @@ - - - {EA879EE4-1245-4456-AED9-57FDF63577E6} - - - - - - - - - - ..\..\lib\loggerpro\packages\d111\loggerproRT.dproj - - - dmvcframeworkRT.dproj - - - - Default.Personality.12 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 376e3ea9c220d72f7c8409d2056f23e54b17f77c Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Tue, 15 Aug 2023 11:43:47 +0200 Subject: [PATCH 28/31] https://github.com/danieleteti/delphimvcframework/issues/680 --- .gitignore | 1 + README.md | 2 + .../AppControllerU.pas | 174 +- .../AuthenticateAuthorize.dpr | 106 +- .../AuthenticateAuthorize.dproj | 2087 +++++++---------- .../AuthenticationU.pas | 160 +- .../ProjectGroup.groupproj} | 0 .../WebModuleUnit1.dfm | 23 +- .../WebModuleUnit1.pas | 118 +- .../bin}/www/index.html | 34 +- .../AuthenticationAuthorizationClient.dpr | 0 .../AuthenticationAuthorizationClient.dproj | 934 +++----- .../vclclient/MainClientFormU.dfm | 0 .../vclclient/MainClientFormU.pas | 0 sources/MVCFramework.pas | 256 +- 15 files changed, 1683 insertions(+), 2212 deletions(-) rename samples/{authenticationauthorization => middleware_basicauthentication}/AppControllerU.pas (96%) rename samples/{authenticationauthorization => middleware_basicauthentication}/AuthenticateAuthorize.dpr (96%) rename samples/{authenticationauthorization => middleware_basicauthentication}/AuthenticateAuthorize.dproj (75%) rename samples/{authenticationauthorization => middleware_basicauthentication}/AuthenticationU.pas (96%) rename samples/{authenticationauthorization/ProjectGroup1.groupproj => middleware_basicauthentication/ProjectGroup.groupproj} (100%) rename samples/{authenticationauthorization => middleware_basicauthentication}/WebModuleUnit1.dfm (84%) rename samples/{authenticationauthorization => middleware_basicauthentication}/WebModuleUnit1.pas (87%) rename samples/{authenticationauthorization => middleware_basicauthentication/bin}/www/index.html (96%) rename samples/{authenticationauthorization => middleware_basicauthentication}/vclclient/AuthenticationAuthorizationClient.dpr (100%) rename samples/{authenticationauthorization => middleware_basicauthentication}/vclclient/AuthenticationAuthorizationClient.dproj (77%) rename samples/{authenticationauthorization => middleware_basicauthentication}/vclclient/MainClientFormU.dfm (100%) rename samples/{authenticationauthorization => middleware_basicauthentication}/vclclient/MainClientFormU.pas (100%) diff --git a/.gitignore b/.gitignore index 6a1cf11c..d94145c8 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,4 @@ samples/WineCellarSample/winecellarclient_mobile/Android/Debug/styles.xml samples/WineCellarSample/winecellarclient_mobile/Android/Debug/styles-v21.xml samples/WineCellarSample/winecellarclient_mobile/Android/Debug/WineCellarMobileClient.classes/classes.dex samples/apachemodule/Apache24/logs/httpd.pid +samples/session_file_based/Win32/DEBUG/sessions/ diff --git a/README.md b/README.md index 767b59e8..b71cebb2 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,8 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma > "Thank you for the great framework! We are very happy with this!" -- Andreas +> "I managed to generate an API for my application thanks to this framework, it is truly useful and efficient!" -- J. Urbani + ## What's New in dmvcframework-3.3.0-fluorine (last stable version) diff --git a/samples/authenticationauthorization/AppControllerU.pas b/samples/middleware_basicauthentication/AppControllerU.pas similarity index 96% rename from samples/authenticationauthorization/AppControllerU.pas rename to samples/middleware_basicauthentication/AppControllerU.pas index f48a311f..4c9d907d 100644 --- a/samples/authenticationauthorization/AppControllerU.pas +++ b/samples/middleware_basicauthentication/AppControllerU.pas @@ -1,87 +1,87 @@ -unit AppControllerU; - -interface - -uses - MVCFramework, - MVCFramework.Commons, - MVCFramework.Logger, - Web.HTTPApp; - -type - - [MVCPath('/')] - TApp1MainController = class(TMVCController) - public - [MVCPath('/public')] - [MVCHTTPMethod([httpGET])] - procedure PublicSection; - [MVCPath('/')] - [MVCHTTPMethod([httpGET])] - procedure Index; - end; - - [MVCPath('/admin')] - TAdminController = class(TMVCController) - public - [MVCPath('/role1')] - [MVCProduces('text/html')] - [MVCHTTPMethod([httpGET])] - procedure OnlyRole1; - [MVCPath('/role1')] - [MVCProduces('application/json')] - [MVCHTTPMethod([httpGET])] - procedure OnlyRole1EmittingJSON; - [MVCPath('/role2')] - [MVCProduces('text/html')] - [MVCHTTPMethod([httpGET])] - procedure OnlyRole2; - end; - -implementation - -uses - System.SysUtils; - -{ TApp1MainController } - -procedure TApp1MainController.Index; -begin - Redirect('/index.html'); -end; - -procedure TApp1MainController.PublicSection; -begin - Render('This is a public section'); -end; - -{ TAdminController } - -procedure TAdminController.OnlyRole1; -begin - ContentType := TMVCMediaType.TEXT_PLAIN; - ResponseStream.AppendLine('Hey! Hello ' + Context.LoggedUser.UserName + - ', now you are a logged user and this is a protected content!'); - ResponseStream.AppendLine('As logged user you have the following roles: ' + - sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray)); - RenderResponseStream; -end; - -procedure TAdminController.OnlyRole1EmittingJSON; -begin - ContentType := TMVCMediaType.APPLICATION_JSON; - Render('This is protected content accessible only by user1: parameter = ' + - Context.Request.Params['par1']); -end; - -procedure TAdminController.OnlyRole2; -begin - ContentType := TMVCMediaType.TEXT_PLAIN; - ResponseStream.AppendLine('Hey! Hello ' + Context.LoggedUser.UserName + - ', now you are a logged user and this is a protected content!'); - ResponseStream.AppendLine('As logged user you have the following roles: ' + - sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray)); - RenderResponseStream; -end; - -end. +unit AppControllerU; + +interface + +uses + MVCFramework, + MVCFramework.Commons, + MVCFramework.Logger, + Web.HTTPApp; + +type + + [MVCPath('/')] + TApp1MainController = class(TMVCController) + public + [MVCPath('/public')] + [MVCHTTPMethod([httpGET])] + procedure PublicSection; + [MVCPath('/')] + [MVCHTTPMethod([httpGET])] + procedure Index; + end; + + [MVCPath('/admin')] + TAdminController = class(TMVCController) + public + [MVCPath('/role1')] + [MVCProduces('text/html')] + [MVCHTTPMethod([httpGET])] + procedure OnlyRole1; + [MVCPath('/role1')] + [MVCProduces('application/json')] + [MVCHTTPMethod([httpGET])] + procedure OnlyRole1EmittingJSON; + [MVCPath('/role2')] + [MVCProduces('text/html')] + [MVCHTTPMethod([httpGET])] + procedure OnlyRole2; + end; + +implementation + +uses + System.SysUtils; + +{ TApp1MainController } + +procedure TApp1MainController.Index; +begin + Redirect('/index.html'); +end; + +procedure TApp1MainController.PublicSection; +begin + Render('This is a public section'); +end; + +{ TAdminController } + +procedure TAdminController.OnlyRole1; +begin + ContentType := TMVCMediaType.TEXT_PLAIN; + ResponseStream.AppendLine('Hey! Hello ' + Context.LoggedUser.UserName + + ', now you are a logged user and this is a protected content!'); + ResponseStream.AppendLine('As logged user you have the following roles: ' + + sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray)); + RenderResponseStream; +end; + +procedure TAdminController.OnlyRole1EmittingJSON; +begin + ContentType := TMVCMediaType.APPLICATION_JSON; + Render('This is protected content accessible only by user1: parameter = ' + + Context.Request.Params['par1']); +end; + +procedure TAdminController.OnlyRole2; +begin + ContentType := TMVCMediaType.TEXT_PLAIN; + ResponseStream.AppendLine('Hey! Hello ' + Context.LoggedUser.UserName + + ', now you are a logged user and this is a protected content!'); + ResponseStream.AppendLine('As logged user you have the following roles: ' + + sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray)); + RenderResponseStream; +end; + +end. diff --git a/samples/authenticationauthorization/AuthenticateAuthorize.dpr b/samples/middleware_basicauthentication/AuthenticateAuthorize.dpr similarity index 96% rename from samples/authenticationauthorization/AuthenticateAuthorize.dpr rename to samples/middleware_basicauthentication/AuthenticateAuthorize.dpr index ef11620c..fd538d1e 100644 --- a/samples/authenticationauthorization/AuthenticateAuthorize.dpr +++ b/samples/middleware_basicauthentication/AuthenticateAuthorize.dpr @@ -1,53 +1,53 @@ -program AuthenticateAuthorize; - -{$APPTYPE CONSOLE} - -uses - System.SysUtils, -{$IFDEF MSWINDOWS} - Winapi.Windows, - Winapi.ShellAPI, -{$ENDIF} - Web.WebReq, - Web.WebBroker, - IdHTTPWebBrokerBridge, - WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule} , - AppControllerU in 'AppControllerU.pas', - MVCFramework.Middleware.Authentication - in '..\..\sources\MVCFramework.Middleware.Authentication.pas', - AuthenticationU in 'AuthenticationU.pas'; - -{$R *.res} - -procedure RunServer(APort: Integer); -var - LServer: TIdHTTPWebBrokerBridge; -begin - Writeln(Format('Starting HTTP Server or port %d', [APort])); - LServer := TIdHTTPWebBrokerBridge.Create(nil); - try - LServer.DefaultPort := APort; - LServer.Active := True; - Writeln('Press RETURN to stop the server'); - {$IFDEF MSWINDOWS} - ShellExecute(0, 'open', PChar('http://localhost:' + IntToStr(APort) + '/static'), nil, nil, SW_SHOW); - {$ENDIF} - ReadLn; - finally - LServer.Free; - end; -end; - -begin - ReportMemoryLeaksOnShutdown := True; - try - if WebRequestHandler <> nil then - WebRequestHandler.WebModuleClass := WebModuleClass; - WebRequestHandlerProc.MaxConnections := 1024; - RunServer(8080); - except - on E: Exception do - Writeln(E.ClassName, ': ', E.Message); - end - -end. +program AuthenticateAuthorize; + +{$APPTYPE CONSOLE} + +uses + System.SysUtils, +{$IFDEF MSWINDOWS} + Winapi.Windows, + Winapi.ShellAPI, +{$ENDIF} + Web.WebReq, + Web.WebBroker, + IdHTTPWebBrokerBridge, + WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule} , + AppControllerU in 'AppControllerU.pas', + MVCFramework.Middleware.Authentication + in '..\..\sources\MVCFramework.Middleware.Authentication.pas', + AuthenticationU in 'AuthenticationU.pas'; + +{$R *.res} + +procedure RunServer(APort: Integer); +var + LServer: TIdHTTPWebBrokerBridge; +begin + Writeln(Format('Starting HTTP Server or port %d', [APort])); + LServer := TIdHTTPWebBrokerBridge.Create(nil); + try + LServer.DefaultPort := APort; + LServer.Active := True; + Writeln('Press RETURN to stop the server'); + {$IFDEF MSWINDOWS} + ShellExecute(0, 'open', PChar('http://localhost:' + IntToStr(APort) + '/static'), nil, nil, SW_SHOW); + {$ENDIF} + ReadLn; + finally + LServer.Free; + end; +end; + +begin + ReportMemoryLeaksOnShutdown := True; + try + if WebRequestHandler <> nil then + WebRequestHandler.WebModuleClass := WebModuleClass; + WebRequestHandlerProc.MaxConnections := 1024; + RunServer(8080); + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end + +end. diff --git a/samples/authenticationauthorization/AuthenticateAuthorize.dproj b/samples/middleware_basicauthentication/AuthenticateAuthorize.dproj similarity index 75% rename from samples/authenticationauthorization/AuthenticateAuthorize.dproj rename to samples/middleware_basicauthentication/AuthenticateAuthorize.dproj index 30387c68..4d73eccc 100644 --- a/samples/authenticationauthorization/AuthenticateAuthorize.dproj +++ b/samples/middleware_basicauthentication/AuthenticateAuthorize.dproj @@ -1,1180 +1,907 @@ - - - {7B54055A-5749-4136-9FE2-35FDBEEA874C} - 19.1 - VCL - AuthenticateAuthorize.dpr - True - Debug - Win32 - 1 - Console - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_1 - true - true - - - true - Base - true - - - true - Cfg_2 - true - true - - - $(BDS)\bin\delphi_PROJECTICNS.icns - AuthenticateAuthorize - ..\..\sources;..\..\lib\delphistompclient;..\..\lib\loggerpro;..\..\lib\dmustache;$(DCC_UnitSearchPath) - CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= - None - 1040 - $(BDS)\bin\delphi_PROJECTICON.ico - System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) - .\$(Platform)\$(Config) - .\$(Platform)\$(Config) - false - false - false - false - false - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - 1033 - cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;JvDotNetCtrls;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;JvXPCtrls;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;FMXfrx17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;CloudService;dxPScxCommonRS17;FmxTeeUI;frxDB17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;JvRuntimeDesign;dxPScxVGridLnkRS17;JclDeveloperTools;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;MyFrameTestPackage;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;fs17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;DataBindingsVCL170;dxSkinOffice2010SilverRS17;vcldbx;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DataBindings;DBXOdbcDriver;IcsCommonDXE3Run;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;FMXTee;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;Jcl;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;Intraweb;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;fsDB17;inet;dorm_runtime_xe3;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;inetdbbde;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;MetropolisUILiveTile;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;vclribbon;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;CodeSiteExpressPkg;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;JvDocking;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;frx17;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;JclContainers;NxAddonsRun_dxe3;CPortLibDXE;JvSystem;dxorgcRS17;svnui;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;FMXfrxDB17;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;JclVcl;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;frxe17;svn;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;bdertl;VirtualTreesR;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage) - - - cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;dxPScxCommonRS17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;dxPScxVGridLnkRS17;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;dxSkinOffice2010SilverRS17;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DBXOdbcDriver;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;inet;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;NxAddonsRun_dxe3;JvSystem;dxorgcRS17;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage) - - - DEBUG;$(DCC_Define) - true - false - true - true - true - - - 3 - true - 1033 - false - - - false - RELEASE;$(DCC_Define) - 0 - 0 - - - 1033 - - - - MainSource - - -
WebModule1
- TWebModule -
- - - - - Cfg_2 - Base - - - Base - - - Cfg_1 - Base - -
- - Delphi.Personality.12 - - - - - False - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1040 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - - - - - - - - - AuthenticateAuthorize.dpr - - - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - FastReport 6.0 Tee Components - - - - - - AuthenticateAuthorize.exe - true - - - - - 1 - - - 0 - - - - - classes - 1 - - - classes - 1 - - - - - res\xml - 1 - - - res\xml - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\armeabi - 1 - - - library\lib\armeabi - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\mips - 1 - - - library\lib\mips - 1 - - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\values-v21 - 1 - - - res\values-v21 - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-ldpi - 1 - - - res\drawable-ldpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-small - 1 - - - res\drawable-small - 1 - - - - - res\drawable-normal - 1 - - - res\drawable-normal - 1 - - - - - res\drawable-large - 1 - - - res\drawable-large - 1 - - - - - res\drawable-xlarge - 1 - - - res\drawable-xlarge - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - 1 - - - 1 - - - 0 - - - - - 1 - .framework - - - 1 - .framework - - - 0 - - - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .dll;.bpl - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .bpl - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(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 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(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 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - - 1 - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - - - - - - - - - - - True - False - - - 12 - - - - -
+ + + {7B54055A-5749-4136-9FE2-35FDBEEA874C} + 19.5 + VCL + AuthenticateAuthorize.dpr + True + Debug + Win32 + 1 + Console + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + $(BDS)\bin\delphi_PROJECTICNS.icns + AuthenticateAuthorize + ..\..\sources;..\..\lib\delphistompclient;..\..\lib\loggerpro;..\..\lib\dmustache;$(DCC_UnitSearchPath) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + None + 1040 + $(BDS)\bin\delphi_PROJECTICON.ico + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + .\$(Platform)\$(Config) + .\bin + false + false + false + false + false + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + 1033 + cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;JvDotNetCtrls;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;JvXPCtrls;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;FMXfrx17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;CloudService;dxPScxCommonRS17;FmxTeeUI;frxDB17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;JvRuntimeDesign;dxPScxVGridLnkRS17;JclDeveloperTools;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;MyFrameTestPackage;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;fs17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;DataBindingsVCL170;dxSkinOffice2010SilverRS17;vcldbx;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DataBindings;DBXOdbcDriver;IcsCommonDXE3Run;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;FMXTee;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;Jcl;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;Intraweb;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;fsDB17;inet;dorm_runtime_xe3;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;inetdbbde;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;MetropolisUILiveTile;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;vclribbon;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;CodeSiteExpressPkg;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;JvDocking;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;frx17;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;JclContainers;NxAddonsRun_dxe3;CPortLibDXE;JvSystem;dxorgcRS17;svnui;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;FMXfrxDB17;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;JclVcl;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;frxe17;svn;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;bdertl;VirtualTreesR;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage) + + + cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;dxPScxCommonRS17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;dxPScxVGridLnkRS17;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;dxSkinOffice2010SilverRS17;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DBXOdbcDriver;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;inet;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;NxAddonsRun_dxe3;JvSystem;dxorgcRS17;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + 3 + true + 1033 + false + none + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + 1033 + + + + MainSource + + +
WebModule1
+ TWebModule +
+ + + + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + Delphi.Personality.12 + + + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1040 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + + + + AuthenticateAuthorize.dpr + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + + 1 + + + 0 + + + + + classes + 64 + + + classes + 64 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + 1 + + + 0 + + + + + 1 + .framework + + + 1 + .framework + + + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/samples/authenticationauthorization/AuthenticationU.pas b/samples/middleware_basicauthentication/AuthenticationU.pas similarity index 96% rename from samples/authenticationauthorization/AuthenticationU.pas rename to samples/middleware_basicauthentication/AuthenticationU.pas index cc6737d2..0f5f1bf3 100644 --- a/samples/authenticationauthorization/AuthenticationU.pas +++ b/samples/middleware_basicauthentication/AuthenticationU.pas @@ -1,80 +1,80 @@ -unit AuthenticationU; - -interface - -uses - System.SysUtils, MVCFramework.Commons, System.Generics.Collections, - MVCFramework; - -type - TAuthenticationSample = class(TInterfacedObject, IMVCAuthenticationHandler) - protected - procedure OnRequest(const AContext: TWebContext; const ControllerQualifiedClassName: string; - const ActionName: string; var AuthenticationRequired: Boolean); - procedure OnAuthentication(const AContext: TWebContext; const UserName: string; const Password: string; - UserRoles: System.Generics.Collections.TList; - var IsValid: Boolean; const SessionData: TSessionData); - procedure OnAuthorization(const AContext: TWebContext; UserRoles - : System.Generics.Collections.TList; - const ControllerQualifiedClassName: string; const ActionName: string; - var IsAuthorized: Boolean); - end; - -implementation - -{ TMVCAuthorization } - -procedure TAuthenticationSample.OnAuthentication(const AContext: TWebContext; const UserName: string; - const Password: string; - UserRoles: System.Generics.Collections.TList; - var IsValid: Boolean; const SessionData: TSessionData); -begin - IsValid := UserName.Equals(Password); // hey!, this is just a demo!!! - if IsValid then - begin - if UserName = 'user1' then - begin - UserRoles.Add('role1'); - end; - if UserName = 'user2' then - begin - UserRoles.Add('role2'); - end; - if UserName = 'user3' then // all the roles - begin - UserRoles.Add('role1'); - UserRoles.Add('role2'); - end; - end - else - begin - UserRoles.Clear; - end; -end; - -procedure TAuthenticationSample.OnAuthorization - (const AContext: TWebContext; UserRoles - : System.Generics.Collections.TList; - const ControllerQualifiedClassName: string; const ActionName: string; - var IsAuthorized: Boolean); -begin - IsAuthorized := False; - if ActionName = 'Logout' then - IsAuthorized := True; // you can always call logout - if ActionName = 'OnlyRole2' then - IsAuthorized := UserRoles.Contains('role2'); - if ActionName = 'OnlyRole1' then - IsAuthorized := UserRoles.Contains('role1'); - if ActionName = 'OnlyRole1EmittingJSON' then - IsAuthorized := UserRoles.Contains('role1'); -end; - -procedure TAuthenticationSample.OnRequest(const AContext: TWebContext; const ControllerQualifiedClassName: string; - const ActionName: string; var AuthenticationRequired: Boolean); -begin - AuthenticationRequired := ControllerQualifiedClassName = - 'AppControllerU.TAdminController'; - -end; - -end. +unit AuthenticationU; + +interface + +uses + System.SysUtils, MVCFramework.Commons, System.Generics.Collections, + MVCFramework; + +type + TAuthenticationSample = class(TInterfacedObject, IMVCAuthenticationHandler) + protected + procedure OnRequest(const AContext: TWebContext; const ControllerQualifiedClassName: string; + const ActionName: string; var AuthenticationRequired: Boolean); + procedure OnAuthentication(const AContext: TWebContext; const UserName: string; const Password: string; + UserRoles: System.Generics.Collections.TList; + var IsValid: Boolean; const SessionData: TSessionData); + procedure OnAuthorization(const AContext: TWebContext; UserRoles + : System.Generics.Collections.TList; + const ControllerQualifiedClassName: string; const ActionName: string; + var IsAuthorized: Boolean); + end; + +implementation + +{ TMVCAuthorization } + +procedure TAuthenticationSample.OnAuthentication(const AContext: TWebContext; const UserName: string; + const Password: string; + UserRoles: System.Generics.Collections.TList; + var IsValid: Boolean; const SessionData: TSessionData); +begin + IsValid := UserName.Equals(Password); // hey!, this is just a demo!!! + if IsValid then + begin + if UserName = 'user1' then + begin + UserRoles.Add('role1'); + end; + if UserName = 'user2' then + begin + UserRoles.Add('role2'); + end; + if UserName = 'user3' then // all the roles + begin + UserRoles.Add('role1'); + UserRoles.Add('role2'); + end; + end + else + begin + UserRoles.Clear; + end; +end; + +procedure TAuthenticationSample.OnAuthorization + (const AContext: TWebContext; UserRoles + : System.Generics.Collections.TList; + const ControllerQualifiedClassName: string; const ActionName: string; + var IsAuthorized: Boolean); +begin + IsAuthorized := False; + if ActionName = 'Logout' then + IsAuthorized := True; // you can always call logout + if ActionName = 'OnlyRole2' then + IsAuthorized := UserRoles.Contains('role2'); + if ActionName = 'OnlyRole1' then + IsAuthorized := UserRoles.Contains('role1'); + if ActionName = 'OnlyRole1EmittingJSON' then + IsAuthorized := UserRoles.Contains('role1'); +end; + +procedure TAuthenticationSample.OnRequest(const AContext: TWebContext; const ControllerQualifiedClassName: string; + const ActionName: string; var AuthenticationRequired: Boolean); +begin + AuthenticationRequired := ControllerQualifiedClassName = + 'AppControllerU.TAdminController'; + +end; + +end. diff --git a/samples/authenticationauthorization/ProjectGroup1.groupproj b/samples/middleware_basicauthentication/ProjectGroup.groupproj similarity index 100% rename from samples/authenticationauthorization/ProjectGroup1.groupproj rename to samples/middleware_basicauthentication/ProjectGroup.groupproj diff --git a/samples/authenticationauthorization/WebModuleUnit1.dfm b/samples/middleware_basicauthentication/WebModuleUnit1.dfm similarity index 84% rename from samples/authenticationauthorization/WebModuleUnit1.dfm rename to samples/middleware_basicauthentication/WebModuleUnit1.dfm index b43b8558..2c58d387 100644 --- a/samples/authenticationauthorization/WebModuleUnit1.dfm +++ b/samples/middleware_basicauthentication/WebModuleUnit1.dfm @@ -1,12 +1,11 @@ -object WebModule1: TWebModule1 - OldCreateOrder = False - OnCreate = WebModuleCreate - Actions = < - item - Default = True - Name = 'DefaultHandler' - PathInfo = '/' - end> - Height = 230 - Width = 415 -end +object WebModule1: TWebModule1 + OnCreate = WebModuleCreate + Actions = < + item + Default = True + Name = 'DefaultHandler' + PathInfo = '/' + end> + Height = 230 + Width = 415 +end diff --git a/samples/authenticationauthorization/WebModuleUnit1.pas b/samples/middleware_basicauthentication/WebModuleUnit1.pas similarity index 87% rename from samples/authenticationauthorization/WebModuleUnit1.pas rename to samples/middleware_basicauthentication/WebModuleUnit1.pas index 146a9bd1..addec183 100644 --- a/samples/authenticationauthorization/WebModuleUnit1.pas +++ b/samples/middleware_basicauthentication/WebModuleUnit1.pas @@ -1,58 +1,60 @@ -unit WebModuleUnit1; - -interface - -uses - System.SysUtils, - System.Classes, - Web.HTTPApp, - MVCFramework, - MVCFramework.Commons; - -type - TWebModule1 = class(TWebModule) - procedure WebModuleCreate(Sender: TObject); - - private - MVC: TMVCEngine; - - public - { Public declarations } - end; - -var - WebModuleClass: TComponentClass = TWebModule1; - -implementation - -{$R *.dfm} - - -uses - AppControllerU, - System.Generics.Collections, - MVCFramework.Middleware.Authentication, - MVCFramework.Middleware.StaticFiles, - AuthenticationU; - -procedure TWebModule1.WebModuleCreate(Sender: TObject); -begin - MVC := TMVCEngine.Create(Self, - procedure(Config: TMVCConfig) - begin - Config[TMVCConfigKey.SessionTimeout] := '30'; - Config[TMVCConfigKey.DefaultContentType] := 'text/html'; - end); - MVC - .AddController(TApp1MainController) - .AddController(TAdminController) - .AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(TAuthenticationSample.Create)) - .AddMiddleware(TMVCStaticFilesMiddleware.Create( - '/static', { StaticFilesPath } - '..\..\www', { DocumentRoot } - 'index.html', - False { not serving a SPA } - )); -end; - -end. +unit WebModuleUnit1; + +interface + +uses + System.SysUtils, + System.Classes, + Web.HTTPApp, + MVCFramework, + MVCFramework.Commons, FireDAC.Phys.PGDef, FireDAC.Stan.Intf, FireDAC.Phys, + FireDAC.Phys.PG; + +type + TWebModule1 = class(TWebModule) + procedure WebModuleCreate(Sender: TObject); + + private + MVC: TMVCEngine; + + public + { Public declarations } + end; + +var + WebModuleClass: TComponentClass = TWebModule1; + +implementation + +{$R *.dfm} + + +uses + AppControllerU, + System.Generics.Collections, + MVCFramework.Middleware.Authentication, + MVCFramework.Middleware.ActiveRecord, + MVCFramework.Middleware.StaticFiles, + AuthenticationU; + +procedure TWebModule1.WebModuleCreate(Sender: TObject); +begin + MVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + Config[TMVCConfigKey.SessionTimeout] := '30'; + Config[TMVCConfigKey.DefaultContentType] := 'text/html'; + end); + MVC + .AddController(TApp1MainController) + .AddController(TAdminController) + .AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(TAuthenticationSample.Create)) + .AddMiddleware(TMVCStaticFilesMiddleware.Create( + '/static', { StaticFilesPath } + 'www', { DocumentRoot } + 'index.html', + False { not serving a SPA } + )); +end; + +end. diff --git a/samples/authenticationauthorization/www/index.html b/samples/middleware_basicauthentication/bin/www/index.html similarity index 96% rename from samples/authenticationauthorization/www/index.html rename to samples/middleware_basicauthentication/bin/www/index.html index d95da22f..e79e5c34 100644 --- a/samples/authenticationauthorization/www/index.html +++ b/samples/middleware_basicauthentication/bin/www/index.html @@ -1,18 +1,18 @@ - - -

Here's the public and the private sections on this application server

- -

- The available users are shown below: -

    -
  • user1/user1 (role1)
  • -
  • user2/user2 (role2)
  • -
  • user3/user3 (role1, role2)
  • -
-

- + + +

Here's the public and the private sections on this application server

+ +

+ The available users are shown below: +

    +
  • user1/user1 (role1)
  • +
  • user2/user2 (role2)
  • +
  • user3/user3 (role1, role2)
  • +
+

+ \ No newline at end of file diff --git a/samples/authenticationauthorization/vclclient/AuthenticationAuthorizationClient.dpr b/samples/middleware_basicauthentication/vclclient/AuthenticationAuthorizationClient.dpr similarity index 100% rename from samples/authenticationauthorization/vclclient/AuthenticationAuthorizationClient.dpr rename to samples/middleware_basicauthentication/vclclient/AuthenticationAuthorizationClient.dpr diff --git a/samples/authenticationauthorization/vclclient/AuthenticationAuthorizationClient.dproj b/samples/middleware_basicauthentication/vclclient/AuthenticationAuthorizationClient.dproj similarity index 77% rename from samples/authenticationauthorization/vclclient/AuthenticationAuthorizationClient.dproj rename to samples/middleware_basicauthentication/vclclient/AuthenticationAuthorizationClient.dproj index fda121a9..87a5b116 100644 --- a/samples/authenticationauthorization/vclclient/AuthenticationAuthorizationClient.dproj +++ b/samples/middleware_basicauthentication/vclclient/AuthenticationAuthorizationClient.dproj @@ -1,7 +1,7 @@  {E7317702-64D3-4A65-8734-030F3AE3DBBC} - 19.1 + 19.5 VCL AuthenticationAuthorizationClient.dpr True @@ -68,7 +68,8 @@ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 1033 DBXSqliteDriver;DBXDb2Driver;dxCoreRS23;vclactnband;frxe23;vclFireDAC;dxPSLnksRS23;dxPSdxLCLnkRS23;tethering;cxDataRS23;dxPSdxOCLnkRS23;dxTabbedMDIRS23;FireDACADSDriver;dxSkinBlackRS23;dxSkinLondonLiquidSkyRS23;JvPluginSystem;dxDBXServerModeRS23;dxHttpIndyRequestRS23;dxPScxGridLnkRS23;cxSchedulerRS23;FireDACMSSQLDriver;dclRBDBE1723;vcltouch;JvBands;vcldb;rbDB1723;svn;dxWizardControlRS23;dxSkinMcSkinRS23;dxPScxCommonRS23;JvJans;Intraweb;dxSkinOffice2007BlueRS23;rbIBE1723;dxBarRS23;cxSchedulerRibbonStyleEventEditorRS23;dxSkinOffice2013WhiteRS23;JvDotNetCtrls;dxPSTeeChartRS23;cxLibraryRS23;dxSkinVisualStudio2013LightRS23;vclib;cxPivotGridChartRS23;rbDBE1723;dxSkinSummer2008RS23;dxPSdxDBOCLnkRS23;dxGDIPlusRS23;dxSkinDarkSideRS23;FireDACDBXDriver;dxSkinFoggyRS23;dxSkinSevenRS23;vclx;rbCIDE1723;dxSkinOffice2010SilverRS23;dxdborRS23;RESTBackendComponents;dxLayoutControlRS23;dxPSPrVwRibbonRS23;VCLRESTComponents;dxSkinDevExpressStyleRS23;dxSkinWhiteprintRS23;vclie;bindengine;CloudService;rbRAP1723;JvHMI;FireDACMySQLDriver;dxSkinOffice2013DarkGrayRS23;DataSnapClient;dxPScxPCProdRS23;bindcompdbx;DBXSybaseASEDriver;IndyIPServer;dxSkinPumpkinRS23;IndySystem;dsnapcon;cxTreeListdxBarPopupMenuRS23;dclRBIBE1723;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;dxSkinLilianRS23;Jcl;rbADO1723;dxBarDBNavRS23;dxFlowChartRS23;dxSkinOffice2016ColorfulRS23;rbUSER1723;DBXOdbcDriver;FireDACTDataDriver;FMXTee;ipstudiowinclient;soaprtl;DbxCommonDriver;dxSpreadSheetRS23;AsyncProDR;JvManagedThreads;dxSkinOffice2007PinkRS23;dxPSdxSpreadSheetLnkRS23;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;DTKANPRPackage;dxSkinHighContrastRS23;rtl;dxSkinSevenClassicRS23;DbxClientDriver;dxSkinDevExpressDarkStyleRS23;DBXSybaseASADriver;dxNavBarRS23;dxSkinMetropolisDarkRS23;CodeSiteExpressPkg;dxSkinTheAsphaltWorldRS23;JvSystem;SampleListViewMultiDetailAppearancePackage;dxRichEditControlRS23;JvStdCtrls;JvTimeFramework;ipstudiowin;appanalytics;cxPivotGridRS23;rbUSERDesign1723;dxSkinsdxDLPainterRS23;IndyIPClient;dxRibbonRS23;dxPScxVGridLnkRS23;bindcompvcl;frxDB23;vcldbx;dxSkinOffice2007SilverRS23;dxPScxTLLnkRS23;dxMapControlRS23;TeeUI;rbDIDE1723;JvPascalInterpreter;JvDocking;VclSmp;dxPScxSchedulerLnkRS23;cxTreeListRS23;FireDACODBCDriver;JclVcl;DataSnapIndy10ServerTransport;dxRibbonCustomizationFormRS23;dxPSRichEditControlLnkRS23;dxBarExtDBItemsRS23;DataSnapProviderClient;FireDACMongoDBDriver;dxSkiniMaginaryRS23;frx23;dxSpellCheckerRS23;JvControls;dxSkinsdxBarPainterRS23;JvPrintPreview;dxSkinCoffeeRS23;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;rbRTL1723;dxADOServerModeRS23;emsclientfiredac;DataSnapFireDAC;svnui;dxmdsRS23;dxSkinLiquidSkyRS23;dxdbtrRS23;dxSkinSpringTimeRS23;dxPSDBTeeChartRS23;JvGlobus;dxSkinscxPCPainterRS23;dxPSCoreRS23;DBXMSSQLDriver;JvMM;dxSkinXmas2008BlueRS23;rbDAD1723;DatasnapConnectorsFreePascal;bindcompfmx;JvNet;DBXOracleDriver;dxSkinSilverRS23;dxSkinValentineRS23;inetdb;JvAppFrm;ipstudiowinwordxp;rbTC1723;FmxTeeUI;dxBarExtItemsRS23;FireDACIBDriver;fmx;fmxdae;DelphiCookbookListViewAppearance;dxServerModeRS23;dxPsPrVwAdvRS23;dxSkinOffice2010BlackRS23;JvWizards;cxPageControlRS23;dxSkinStardustRS23;cxSchedulerGridRS23;dbexpress;IndyCore;dxSkinSharpPlusRS23;UIBD21Win32R;JvPageComps;dsnap;DataSnapCommon;emsclient;FireDACCommon;dxSkinOffice2010BlueRS23;bdertl;JvDB;dxSkinVS2010RS23;dxSkinMetropolisRS23;DataSnapConnectors;cxVerticalGridRS23;soapserver;dxSkinCaramelRS23;frxTee23;dxTileControlRS23;JclDeveloperTools;cxGridRS23;CPortLibDXE;FireDACOracleDriver;DBXMySQLDriver;JvCmp;rbFireDAC1723;DBXFirebirdDriver;FireDACCommonDriver;rbTCUI1723;LockBoxDR;inet;IndyIPCommon;JvCustom;dxSkinDarkRoomRS23;dxDockingRS23;vcl;dxSkinOffice2007GreenRS23;dxPScxExtCommonRS23;JvXPCtrls;dxSkinsCoreRS23;FireDACDb2Driver;dxThemeRS23;dxSkinsdxRibbonPainterRS23;dxSkinVisualStudio2013BlueRS23;rbRest1723;TSG5201;dxSkinMoneyTwinsRS23;dxPSdxFCLnkRS23;dxtrmdRS23;TeeDB;FireDAC;cxSchedulerTreeBrowserRS23;JvCore;dxFireDACServerModeRS23;dxSkinBlueRS23;OverbyteIcsD10SRun;JvCrypt;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;cxEditorsRS23;dxSkinGlassOceansRS23;JvDlgs;JvRuntimeDesign;dxSkinsdxNavBarPainterRS23;dxGaugeControlRS23;ibxpress;Tee;dxSkinSharpRS23;DataSnapServer;ibxbindings;cxPivotGridOLAPRS23;rbIDE1723;vclwinx;FireDACDSDriver;dxSkinBlueprintRS23;dxSkinOffice2007BlackRS23;CustomIPTransport;vcldsnap;rbBDE1723;dxSkinOffice2013LightGrayRS23;bindcomp;DBXInformixDriver;officeXPrt;dxPSdxGaugeControlLnkRS23;dxPScxPivotGridLnkRS23;dxorgcRS23;dxPSdxDBTVLnkRS23;dclRBADO1723;vclribbon;dbxcds;KernowSoftwareFMX;adortl;dclRBFireDAC1723;dclRBE1723;dxComnRS23;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;cxExportRS23;dxSkinOffice2016DarkRS23;JclContainers;dxSkinVisualStudio2013DarkRS23;rbRCL1723;dxSkinscxSchedulerPainterRS23;rbRIDE1723;fmxase;$(DCC_UsePackage) - CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(ModuleName);FileDescription=$(ModuleName);ProductName=$(ModuleName) + ..\bin + none $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png @@ -87,9 +88,7 @@ Debug true 1033 - true false - CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(ModuleName);FileDescription=$(ModuleName);ProductName=$(ModuleName) PerMonitor @@ -110,10 +109,6 @@
Form5
dfm
- - Cfg_2 - Base - Base @@ -121,6 +116,10 @@ Cfg_1 Base + + Cfg_2 + Base + Delphi.Personality.12 @@ -131,19 +130,14 @@ AuthenticationAuthorizationClient.dpr - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components - - - - AuthenticationAuthorizationClient.exe - true - - + + 1 @@ -156,14 +150,14 @@ 0 - + classes - 1 + 64 classes - 1 + 64 @@ -208,7 +202,6 @@ 1 - library\lib\armeabi-v7a @@ -285,6 +278,16 @@ 1 + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + res\drawable-ldpi @@ -448,6 +451,11 @@ 1 .framework + + Contents\MacOS + 1 + .framework + 0 @@ -461,7 +469,7 @@ 1 .dylib - + 1 .dylib @@ -475,6 +483,11 @@ 1 .dylib + + Contents\MacOS + 1 + .dylib + 0 .dll;.bpl @@ -489,7 +502,7 @@ 1 .dylib - + 1 .dylib @@ -503,6 +516,11 @@ 1 .dylib + + Contents\MacOS + 1 + .dylib + 0 .bpl @@ -521,7 +539,7 @@ 0 - + 0 @@ -532,512 +550,12 @@ Contents\Resources\StartUp\ 0 - + + Contents\Resources\StartUp\ 0 - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(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 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(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 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 + + 0 @@ -1048,71 +566,15 @@ 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - 1 - - - 1 - - - - - ..\ - 1 - - - ..\ - 1 - - - - - 1 - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).launchscreen - 64 - - - ..\$(PROJECTNAME).launchscreen - 64 - - - - - 1 - - - 1 - - - 1 - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1 + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + @@ -1123,6 +585,10 @@ ..\ 1 + + ..\ + 1 + @@ -1133,6 +599,10 @@ Contents 1 + + Contents + 1 + @@ -1143,6 +613,10 @@ Contents\Resources 1 + + Contents\Resources + 1 + @@ -1159,7 +633,7 @@ 1 - + 1 @@ -1173,6 +647,10 @@ Contents\MacOS 1 + + Contents\MacOS + 1 + 0 @@ -1191,6 +669,66 @@ 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).launchscreen + 64 + + + ..\$(PROJECTNAME).launchscreen + 64 + + + + + 1 + + + 1 + + + 1 + + Assets @@ -1211,16 +749,218 @@ 1 - - + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + - + + + - - - + + + True diff --git a/samples/authenticationauthorization/vclclient/MainClientFormU.dfm b/samples/middleware_basicauthentication/vclclient/MainClientFormU.dfm similarity index 100% rename from samples/authenticationauthorization/vclclient/MainClientFormU.dfm rename to samples/middleware_basicauthentication/vclclient/MainClientFormU.dfm diff --git a/samples/authenticationauthorization/vclclient/MainClientFormU.pas b/samples/middleware_basicauthentication/vclclient/MainClientFormU.pas similarity index 100% rename from samples/authenticationauthorization/vclclient/MainClientFormU.pas rename to samples/middleware_basicauthentication/vclclient/MainClientFormU.pas diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index da2a2c1f..aa6556ed 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -2539,155 +2539,155 @@ begin lRouterControllerClazzQualifiedClassName, lRouterMethodToCallName, lHandled); - if lHandled then - Exit(True); - - lBodyParameter := nil; - lSelectedController.MVCControllerAfterCreate; - try - lHandled := False; - lSelectedController.ContentType := BuildContentType(lResponseContentMediaType, - lResponseContentCharset); - lActionFormalParams := lRouter.MethodToCall.GetParameters; - if (Length(lActionFormalParams) = 0) then - SetLength(lActualParams, 0) - else if (Length(lActionFormalParams) = 1) and - (SameText(lActionFormalParams[0].ParamType.QualifiedName, - 'MVCFramework.TWebContext')) then - begin - SetLength(lActualParams, 1); - lActualParams[0] := lContext; - end - else - begin - FillActualParamsForAction(lSelectedController, lContext, lActionFormalParams, - lRouterMethodToCallName, lActualParams, lBodyParameter); - end; - lSelectedController.OnBeforeAction(lContext, lRouterMethodToCallName, lHandled); - if not lHandled then - begin - try - if lRouter.MethodToCall.MethodKind = mkProcedure then - begin - lRouter.MethodToCall.Invoke(lSelectedController, lActualParams); - end - else - begin - lInvokeResult := lRouter.MethodToCall.Invoke(lSelectedController, lActualParams); - case lInvokeResult.Kind of - tkInterface: - begin - if Supports(lInvokeResult.AsInterface, IMVCResponse) then + if not lHandled then + begin + lBodyParameter := nil; + lSelectedController.MVCControllerAfterCreate; + try + lHandled := False; + lSelectedController.ContentType := BuildContentType(lResponseContentMediaType, + lResponseContentCharset); + lActionFormalParams := lRouter.MethodToCall.GetParameters; + if (Length(lActionFormalParams) = 0) then + SetLength(lActualParams, 0) + else if (Length(lActionFormalParams) = 1) and + (SameText(lActionFormalParams[0].ParamType.QualifiedName, + 'MVCFramework.TWebContext')) then + begin + SetLength(lActualParams, 1); + lActualParams[0] := lContext; + end + else + begin + FillActualParamsForAction(lSelectedController, lContext, lActionFormalParams, + lRouterMethodToCallName, lActualParams, lBodyParameter); + end; + lSelectedController.OnBeforeAction(lContext, lRouterMethodToCallName, lHandled); + if not lHandled then + begin + try + if lRouter.MethodToCall.MethodKind = mkProcedure then + begin + lRouter.MethodToCall.Invoke(lSelectedController, lActualParams); + end + else + begin + lInvokeResult := lRouter.MethodToCall.Invoke(lSelectedController, lActualParams); + case lInvokeResult.Kind of + tkInterface: begin - lResponseObject := TMVCResponse(lInvokeResult.AsInterface); - lSelectedController.ResponseStatus( - TMVCResponse(lResponseObject).StatusCode, - TMVCResponse(lResponseObject).ReasonString); - lSelectedController.Render(TMVCResponse(lResponseObject), False); - end - else - begin - lSelectedController.Render(lInvokeResult.AsInterface); - end; - end; - tkClass: - begin - lResponseObject := lInvokeResult.AsObject; - try - // https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0 - if lResponseObject is TDataSet then - begin - lSelectedController.Render(TDataSet(lResponseObject), False); - end - else if lResponseObject is TStream then - begin - lContext.Response.RawWebResponse.Content := EmptyStr; - lContext.Response.RawWebResponse.ContentType := lContext.Response.ContentType; - lContext.Response.RawWebResponse.ContentStream := TStream(lResponseObject); - lContext.Response.RawWebResponse.FreeContentStream := True; - lResponseObject := nil; //do not free it!! - end - else if lResponseObject is TMVCResponse then + if Supports(lInvokeResult.AsInterface, IMVCResponse) then begin + lResponseObject := TMVCResponse(lInvokeResult.AsInterface); lSelectedController.ResponseStatus( TMVCResponse(lResponseObject).StatusCode, TMVCResponse(lResponseObject).ReasonString); lSelectedController.Render(TMVCResponse(lResponseObject), False); end - else if TDuckTypedList.CanBeWrappedAsList(lResponseObject, lObjList) then - begin - lSelectedController.Render(lObjList); - end else begin - lSelectedController.Render(lResponseObject, False); + lSelectedController.Render(lInvokeResult.AsInterface); end; - finally - lResponseObject.Free; - end - end; - tkRecord: - begin - lSelectedController.Render( - lSelectedController.Serializer(lSelectedController.GetContentType) - .SerializeRecord(lInvokeResult.GetReferenceToRawData, - lInvokeResult.TypeInfo, - TMVCSerializationType.stFields,nil,nil)); - end; - tkArray, tkDynArray: - begin - lSelectedController.Render( - lSelectedController.Serializer(lSelectedController.GetContentType) - .SerializeArrayOfRecord(lInvokeResult, + end; + tkClass: + begin + lResponseObject := lInvokeResult.AsObject; + try + // https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0 + if lResponseObject is TDataSet then + begin + lSelectedController.Render(TDataSet(lResponseObject), False); + end + else if lResponseObject is TStream then + begin + lContext.Response.RawWebResponse.Content := EmptyStr; + lContext.Response.RawWebResponse.ContentType := lContext.Response.ContentType; + lContext.Response.RawWebResponse.ContentStream := TStream(lResponseObject); + lContext.Response.RawWebResponse.FreeContentStream := True; + lResponseObject := nil; //do not free it!! + end + else if lResponseObject is TMVCResponse then + begin + lSelectedController.ResponseStatus( + TMVCResponse(lResponseObject).StatusCode, + TMVCResponse(lResponseObject).ReasonString); + lSelectedController.Render(TMVCResponse(lResponseObject), False); + end + else if TDuckTypedList.CanBeWrappedAsList(lResponseObject, lObjList) then + begin + lSelectedController.Render(lObjList); + end + else + begin + lSelectedController.Render(lResponseObject, False); + end; + finally + lResponseObject.Free; + end + end; + tkRecord: + begin + lSelectedController.Render( + lSelectedController.Serializer(lSelectedController.GetContentType) + .SerializeRecord(lInvokeResult.GetReferenceToRawData, + lInvokeResult.TypeInfo, TMVCSerializationType.stFields,nil,nil)); - end; - tkUString, tkString: - begin - lSelectedController.Render(lInvokeResult.AsString); - end; - tkEnumeration: - begin - lSelectedController.Render(GetEnumName(lInvokeResult.TypeInfo, lInvokeResult.AsOrdinal)); - end; - tkFloat: - begin - lSelectedController.Render(FloatToStr(lInvokeResult.AsExtended, GetDefaultFormatSettings)); - end; - tkInteger: - begin - lSelectedController.Render(IntToStr(lInvokeResult.AsInteger)); - end; - tkInt64: - begin - lSelectedController.Render(IntToStr(lInvokeResult.AsInt64)); - end - else - begin - RaiseSerializationError('Cannot serialize type ' + lInvokeResult.TypeInfo.Name); + end; + tkArray, tkDynArray: + begin + lSelectedController.Render( + lSelectedController.Serializer(lSelectedController.GetContentType) + .SerializeArrayOfRecord(lInvokeResult, + TMVCSerializationType.stFields,nil,nil)); + end; + tkUString, tkString: + begin + lSelectedController.Render(lInvokeResult.AsString); + end; + tkEnumeration: + begin + lSelectedController.Render(GetEnumName(lInvokeResult.TypeInfo, lInvokeResult.AsOrdinal)); + end; + tkFloat: + begin + lSelectedController.Render(FloatToStr(lInvokeResult.AsExtended, GetDefaultFormatSettings)); + end; + tkInteger: + begin + lSelectedController.Render(IntToStr(lInvokeResult.AsInteger)); + end; + tkInt64: + begin + lSelectedController.Render(IntToStr(lInvokeResult.AsInt64)); + end + else + begin + RaiseSerializationError('Cannot serialize type ' + lInvokeResult.TypeInfo.Name); + end; end; end; + finally + lSelectedController.OnAfterAction(lContext, lRouterMethodToCallName); end; - finally - lSelectedController.OnAfterAction(lContext, lRouterMethodToCallName); end; - end; - finally - try - lBodyParameter.Free; - except - on E: Exception do - begin - LogE(Format('Cannot free Body object: [CLS: %s][MSG: %s]', - [E.Classname, E.Message])); + finally + try + lBodyParameter.Free; + except + on E: Exception do + begin + LogE(Format('Cannot free Body object: [CLS: %s][MSG: %s]', + [E.Classname, E.Message])); + end; end; + lSelectedController.MVCControllerBeforeDestroy; end; - lSelectedController.MVCControllerBeforeDestroy; - end; + lContext.Response.ContentType := lSelectedController.ContentType; + end; //if not handled by OnBeforeControllerActionMiddleware ExecuteAfterControllerActionMiddleware(lContext, lRouterControllerClazzQualifiedClassName, lRouterMethodToCallName, lHandled); - lContext.Response.ContentType := lSelectedController.ContentType; fOnRouterLog(lRouter, rlsRouteFound, lContext); end else // execute-routing From e93f9e5ae7ad1c7e6140b328a91dfa97897c82e0 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Tue, 15 Aug 2023 18:24:17 +0200 Subject: [PATCH 29/31] https://github.com/danieleteti/delphimvcframework/issues/679 (WIP) --- samples/middleware_cors/MainControllerU.pas | 105 ++ .../middleware_cors/SPARedirectController.pas | 29 + samples/middleware_cors/WebModuleU.dfm | 7 + samples/middleware_cors/WebModuleU.pas | 86 ++ samples/middleware_cors/bin/www/index.html | 1 + samples/middleware_cors/middleware_cors.dpr | 75 ++ samples/middleware_cors/middleware_cors.dproj | 902 ++++++++++++++++++ sources/MVCFramework.Middleware.CORS.pas | 20 +- 8 files changed, 1218 insertions(+), 7 deletions(-) create mode 100644 samples/middleware_cors/MainControllerU.pas create mode 100644 samples/middleware_cors/SPARedirectController.pas create mode 100644 samples/middleware_cors/WebModuleU.dfm create mode 100644 samples/middleware_cors/WebModuleU.pas create mode 100644 samples/middleware_cors/bin/www/index.html create mode 100644 samples/middleware_cors/middleware_cors.dpr create mode 100644 samples/middleware_cors/middleware_cors.dproj diff --git a/samples/middleware_cors/MainControllerU.pas b/samples/middleware_cors/MainControllerU.pas new file mode 100644 index 00000000..812ad12b --- /dev/null +++ b/samples/middleware_cors/MainControllerU.pas @@ -0,0 +1,105 @@ +unit MainControllerU; + +interface + +uses + MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons; + +type + + [MVCPath('/api')] + TMyController = class(TMVCController) + public + [MVCPath] + [MVCConsumes(TMVCMediaType.TEXT_HTML)] + [MVCHTTPMethod([httpGET])] + procedure Index; + + [MVCPath('/reversedstrings/($Value)')] + [MVCHTTPMethod([httpGET])] + procedure GetReversedString(const Value: string); + protected + procedure OnBeforeAction(Context: TWebContext; const AActionName: string; var Handled: Boolean); override; + procedure OnAfterAction(Context: TWebContext; const AActionName: string); override; + + public + // Sample CRUD Actions for a "Customer" entity + [MVCPath('/customers')] + [MVCHTTPMethod([httpGET])] + procedure GetCustomers; + + [MVCPath('/customers/($id)')] + [MVCHTTPMethod([httpGET])] + procedure GetCustomer(id: Integer); + + [MVCPath('/customers')] + [MVCHTTPMethod([httpPOST])] + procedure CreateCustomer; + + [MVCPath('/customers/($id)')] + [MVCHTTPMethod([httpPUT])] + procedure UpdateCustomer(id: Integer); + + [MVCPath('/customers/($id)')] + [MVCHTTPMethod([httpDELETE])] + procedure DeleteCustomer(id: Integer); + + end; + +implementation + +uses + System.SysUtils, MVCFramework.Logger, System.StrUtils; + +procedure TMyController.Index; +begin + Redirect('/static'); +end; + +procedure TMyController.GetReversedString(const Value: string); +begin + Render(System.StrUtils.ReverseString(Value.Trim)); +end; + +procedure TMyController.OnAfterAction(Context: TWebContext; const AActionName: string); +begin + { Executed after each action } + inherited; +end; + +procedure TMyController.OnBeforeAction(Context: TWebContext; const AActionName: string; var Handled: Boolean); +begin + { Executed before each action + if handled is true (or an exception is raised) the actual + action will not be called } + inherited; +end; + +// Sample CRUD Actions for a "Customer" entity +procedure TMyController.GetCustomers; +begin + // todo: render a list of customers +end; + +procedure TMyController.GetCustomer(id: Integer); +begin + // todo: render the customer by id +end; + +procedure TMyController.CreateCustomer; + +begin + // todo: create a new customer +end; + +procedure TMyController.UpdateCustomer(id: Integer); +begin + // todo: update customer by id +end; + +procedure TMyController.DeleteCustomer(id: Integer); +begin + // todo: delete customer by id +end; + +end. diff --git a/samples/middleware_cors/SPARedirectController.pas b/samples/middleware_cors/SPARedirectController.pas new file mode 100644 index 00000000..347c9f05 --- /dev/null +++ b/samples/middleware_cors/SPARedirectController.pas @@ -0,0 +1,29 @@ +unit SPARedirectController; + +interface + +uses + MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons; + +type + + [MVCPath] + TSPARedirectController = class(TMVCController) + public + [MVCPath('/')] + [MVCProduces(TMVCMediaType.TEXT_HTML)] + [MVCHTTPMethod([httpGET])] + procedure Index; + end; + +implementation + +uses + System.SysUtils, MVCFramework.Logger, System.StrUtils; + +procedure TSPARedirectController.Index; +begin + Redirect('/static'); +end; + +end. diff --git a/samples/middleware_cors/WebModuleU.dfm b/samples/middleware_cors/WebModuleU.dfm new file mode 100644 index 00000000..02d66b97 --- /dev/null +++ b/samples/middleware_cors/WebModuleU.dfm @@ -0,0 +1,7 @@ +object MyWebModule: TMyWebModule + OnCreate = WebModuleCreate + OnDestroy = WebModuleDestroy + Actions = <> + Height = 230 + Width = 415 +end diff --git a/samples/middleware_cors/WebModuleU.pas b/samples/middleware_cors/WebModuleU.pas new file mode 100644 index 00000000..10524579 --- /dev/null +++ b/samples/middleware_cors/WebModuleU.pas @@ -0,0 +1,86 @@ +unit WebModuleU; + +interface + +uses + System.SysUtils, + System.Classes, + Web.HTTPApp, + MVCFramework, + MVCFramework.Logger; + +type + TMyWebModule = class(TWebModule) + procedure WebModuleCreate(Sender: TObject); + procedure WebModuleDestroy(Sender: TObject); + private + FMVC: TMVCEngine; + public + { Public declarations } + end; + +var + WebModuleClass: TComponentClass = TMyWebModule; + +implementation + +{$R *.dfm} + + +uses + MainControllerU, + System.IOUtils, + MVCFramework.Commons, + MVCFramework.Middleware.StaticFiles, + MVCFramework.Middleware.Compression, + MVCFramework.Middleware.CORS, + SPARedirectController; + +procedure TMyWebModule.WebModuleCreate(Sender: TObject); +begin + FMVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + // session timeout (0 means session cookie) + Config[TMVCConfigKey.SessionTimeout] := '0'; + // default content-type + Config[TMVCConfigKey.DefaultContentType] := TMVCConstants.DEFAULT_CONTENT_TYPE; + // default content charset + Config[TMVCConfigKey.DefaultContentCharset] := TMVCConstants.DEFAULT_CONTENT_CHARSET; + // unhandled actions are permitted? + Config[TMVCConfigKey.AllowUnhandledAction] := 'false'; + // default view file extension + Config[TMVCConfigKey.DefaultViewFileExtension] := 'html'; + // view path + Config[TMVCConfigKey.ViewPath] := 'templates'; + // Max Record Count for automatic Entities CRUD + Config[TMVCConfigKey.MaxEntitiesRecordCount] := '20'; + // Enable Server Signature in response + Config[TMVCConfigKey.ExposeServerSignature] := 'true'; + // Max request size in bytes + Config[TMVCConfigKey.MaxRequestSize] := IntToStr(TMVCConstants.DEFAULT_MAX_REQUEST_SIZE); + Config[TMVCConfigKey.LoadSystemControllers] := 'false'; + end); + FMVC + .AddController(TMyController) + .AddController(TSPARedirectController); + + // Required to enable serving of static files + FMVC.AddMiddleware(TMVCCORSMiddleware.Create); + + // Required to enable serving of static files + FMVC.AddMiddleware(TMVCStaticFilesMiddleware.Create( + '/static', + TPath.Combine(ExtractFilePath(GetModuleName(HInstance)), 'www')) + ); + + // To enable compression (deflate, gzip) just add this middleware as the last one + FMVC.AddMiddleware(TMVCCompressionMiddleware.Create); +end; + +procedure TMyWebModule.WebModuleDestroy(Sender: TObject); +begin + FMVC.Free; +end; + +end. diff --git a/samples/middleware_cors/bin/www/index.html b/samples/middleware_cors/bin/www/index.html new file mode 100644 index 00000000..1b363e0f --- /dev/null +++ b/samples/middleware_cors/bin/www/index.html @@ -0,0 +1 @@ +INDEX FILE IN WWW \ No newline at end of file diff --git a/samples/middleware_cors/middleware_cors.dpr b/samples/middleware_cors/middleware_cors.dpr new file mode 100644 index 00000000..99674c13 --- /dev/null +++ b/samples/middleware_cors/middleware_cors.dpr @@ -0,0 +1,75 @@ +program middleware_cors; + +{$APPTYPE CONSOLE} + + +uses + System.SysUtils, + MVCFramework, + MVCFramework.Logger, + MVCFramework.Commons, +{$IFDEF MSWINDOWS} + Winapi.Windows, + Winapi.ShellAPI, +{$ENDIF} + MVCFramework.Signal, + Web.ReqMulti, + Web.WebReq, + Web.WebBroker, + IdContext, + IdHTTPWebBrokerBridge, + MainControllerU in 'MainControllerU.pas', + WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule} , + SPARedirectController in 'SPARedirectController.pas'; + +{$R *.res} + + +procedure RunServer(APort: Integer); +var + LServer: TIdHTTPWebBrokerBridge; +begin + Writeln('** DMVCFramework Server ** build ' + DMVCFRAMEWORK_VERSION); + + LServer := TIdHTTPWebBrokerBridge.Create(nil); + try + LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication; + LServer.DefaultPort := APort; + + { more info about MaxConnections + http://www.indyproject.org/docsite/html/frames.html?frmname=topic&frmfile=TIdCustomTCPServer_MaxConnections.html } + LServer.MaxConnections := 0; + + { more info about ListenQueue + http://www.indyproject.org/docsite/html/frames.html?frmname=topic&frmfile=TIdCustomTCPServer_ListenQueue.html } + LServer.ListenQueue := 200; + + { Comment the next line to avoid the default browser startup } +{$IFDEF MSWINDOWS} + //ShellExecute(0, 'open', PChar('http://localhost:' + inttostr(APort)), nil, nil, SW_SHOWMAXIMIZED); +{$ENDIF} + { required if you use JWT middleware } + LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication; + LServer.Active := True; + Writeln('CTRL+C to shutdown the server'); + WaitForTerminationSignal; + EnterInShutdownState; + finally + LServer.Free; + end; +end; + +begin + ReportMemoryLeaksOnShutdown := True; + IsMultiThread := True; + try + if WebRequestHandler <> nil then + WebRequestHandler.WebModuleClass := WebModuleClass; + WebRequestHandlerProc.MaxConnections := 1024; + RunServer(8080); + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end; + +end. diff --git a/samples/middleware_cors/middleware_cors.dproj b/samples/middleware_cors/middleware_cors.dproj new file mode 100644 index 00000000..f09e2eab --- /dev/null +++ b/samples/middleware_cors/middleware_cors.dproj @@ -0,0 +1,902 @@ + + + {A4AB18DC-0F2D-4D2A-94F8-67D871413D88} + 19.5 + VCL + middleware_cors.dpr + True + Debug + Win32 + 1 + Console + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + true + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\delphi_PROJECTICNS.icns + $(DMVC);$(DCC_UnitSearchPath) + VCL;$(DCC_Framework) + middleware_cors + + + DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;ibxbindings;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage) + android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png + + + DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;ibxbindings;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage) + android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png + + + RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACADSDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;Spring.Data;inetdb;SMCmpntRX103;emsedge;FireDACIBDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;soapserver;bindengine;CloudService;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndySystem;FireDACDb2Driver;FireDACInfxDriver;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;rtl;emsserverresource;DbxClientDriver;CustomIPTransport;bindcomp;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;dbrtl;IndyProtocols;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage) + + + DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;tethering;svnui;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;IconFontsImageList;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;Spring.Data;inetdb;SMCmpntRX103;RaizeComponentsVcl;emsedge;RaizeComponentsVclDb;fmx;FireDACIBDriver;fmxdae;RadiantShapesFmx;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python_D;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IconFontsImageListFMX;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;ibxbindings;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dmvcframeworkRT;dbxcds;VclSmp;adortl;FireDACODBCDriver;RadiantShapesFmx_Design;DataSnapIndy10ServerTransport;dmvcframeworkDT;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + .\bin + (None) + + + DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;tethering;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;Spring.Data;inetdb;RaizeComponentsVcl;emsedge;RaizeComponentsVclDb;fmx;FireDACIBDriver;fmxdae;RadiantShapesFmx;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;ibxbindings;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;RadiantShapesFmx_Design;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + 1033 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + +
MyWebModule
+ TWebModule +
+ + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + Delphi.Personality.12 + Console + + + + middleware_cors.dpr + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + + + + middleware_cors.exe + true + + + + + + 1 + + + 0 + + + + + classes + 64 + + + classes + 64 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + 1 + + + 0 + + + + + 1 + .framework + + + 1 + .framework + + + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + False + False + False + True + False + + + 12 + + + + +
diff --git a/sources/MVCFramework.Middleware.CORS.pas b/sources/MVCFramework.Middleware.CORS.pas index 4851487f..a844f2c8 100644 --- a/sources/MVCFramework.Middleware.CORS.pas +++ b/sources/MVCFramework.Middleware.CORS.pas @@ -63,7 +63,7 @@ type TMVCCORSMiddleware = class(TInterfacedObject, IMVCMiddleware) private FAllowedOriginURL: string; - FAllowsCredentials: string; + FAllowsCredentials: Boolean; FAllowsMethods: string; FExposeHeaders: string; FAllowsHeaders: string; @@ -71,24 +71,24 @@ type procedure OnBeforeRouting( AContext: TWebContext; var AHandled: Boolean - ); + ); virtual; procedure OnBeforeControllerAction( AContext: TWebContext; const AControllerQualifiedClassName: string; const AActionName: string; var AHandled: Boolean - ); + ); virtual; procedure OnAfterControllerAction( AContext: TWebContext; const AControllerQualifiedClassName: string; const AActionName: string; - const AHandled: Boolean); + const AHandled: Boolean); virtual; procedure OnAfterRouting( AContext: TWebContext; const AHandled: Boolean - ); + ); virtual; public constructor Create( @@ -116,7 +116,7 @@ constructor TMVCCORSMiddleware.Create( begin inherited Create; FAllowedOriginURL := AAllowedOriginURL; - FAllowsCredentials := IfThen(AAllowsCredentials, 'true', 'false'); + FAllowsCredentials := AAllowsCredentials; FExposeHeaders := AExposeHeaders; FAllowsHeaders := AAllowsHeaders; FAllowsMethods := AAllowsMethods; @@ -147,7 +147,13 @@ begin AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Origin'] := FAllowedOriginURL; AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Methods'] := FAllowsMethods; AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Headers'] := FAllowsHeaders; - AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Credentials'] := FAllowsCredentials; + + if FAllowsCredentials then + begin + // Omit Access-Control-Allow-Credentials if <> true + // https://github.com/danieleteti/delphimvcframework/issues/679#issuecomment-1676535853 + AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Credentials'] := 'true'; + end; AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Expose-Headers'] := FExposeHeaders; // allows preflight requests From dfe3943d86e1d2a8efef9b2ebd45f1dfc368fbfe Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Tue, 15 Aug 2023 21:25:46 +0200 Subject: [PATCH 30/31] https://github.com/danieleteti/delphimvcframework/issues/679 --- samples/middleware_cors/MainControllerU.pas | 85 +- .../middleware_cors/ProjectGroup.groupproj | 48 + .../middleware_cors/SPARedirectController.pas | 29 - .../SimpleWebServer/SimpleWebServer.dpr | 90 ++ .../SimpleWebServer/SimpleWebServer.dproj | 909 ++++++++++++++++++ .../SimpleWebServer/WebModuleU.dfm | 7 + .../SimpleWebServer/WebModuleU.pas | 125 +++ samples/middleware_cors/WebModuleU.pas | 20 +- samples/middleware_cors/bin/www/index.html | 30 +- samples/middleware_cors/middleware_cors.dpr | 22 +- samples/middleware_cors/middleware_cors.dproj | 1 - sources/MVCFramework.Middleware.CORS.pas | 35 +- 12 files changed, 1257 insertions(+), 144 deletions(-) create mode 100644 samples/middleware_cors/ProjectGroup.groupproj delete mode 100644 samples/middleware_cors/SPARedirectController.pas create mode 100644 samples/middleware_cors/SimpleWebServer/SimpleWebServer.dpr create mode 100644 samples/middleware_cors/SimpleWebServer/SimpleWebServer.dproj create mode 100644 samples/middleware_cors/SimpleWebServer/WebModuleU.dfm create mode 100644 samples/middleware_cors/SimpleWebServer/WebModuleU.pas diff --git a/samples/middleware_cors/MainControllerU.pas b/samples/middleware_cors/MainControllerU.pas index 812ad12b..f386654f 100644 --- a/samples/middleware_cors/MainControllerU.pas +++ b/samples/middleware_cors/MainControllerU.pas @@ -10,40 +10,9 @@ type [MVCPath('/api')] TMyController = class(TMVCController) public - [MVCPath] - [MVCConsumes(TMVCMediaType.TEXT_HTML)] - [MVCHTTPMethod([httpGET])] - procedure Index; - - [MVCPath('/reversedstrings/($Value)')] - [MVCHTTPMethod([httpGET])] - procedure GetReversedString(const Value: string); - protected - procedure OnBeforeAction(Context: TWebContext; const AActionName: string; var Handled: Boolean); override; - procedure OnAfterAction(Context: TWebContext; const AActionName: string); override; - - public - // Sample CRUD Actions for a "Customer" entity - [MVCPath('/customers')] - [MVCHTTPMethod([httpGET])] - procedure GetCustomers; - - [MVCPath('/customers/($id)')] - [MVCHTTPMethod([httpGET])] - procedure GetCustomer(id: Integer); - [MVCPath('/customers')] [MVCHTTPMethod([httpPOST])] - procedure CreateCustomer; - - [MVCPath('/customers/($id)')] - [MVCHTTPMethod([httpPUT])] - procedure UpdateCustomer(id: Integer); - - [MVCPath('/customers/($id)')] - [MVCHTTPMethod([httpDELETE])] - procedure DeleteCustomer(id: Integer); - + procedure CreateCustomer(const [MVCFromBody] Dict: TMVCStringDictionary); end; implementation @@ -51,55 +20,11 @@ implementation uses System.SysUtils, MVCFramework.Logger, System.StrUtils; -procedure TMyController.Index; +procedure TMyController.CreateCustomer(const [MVCFromBody] Dict: TMVCStringDictionary); begin - Redirect('/static'); -end; - -procedure TMyController.GetReversedString(const Value: string); -begin - Render(System.StrUtils.ReverseString(Value.Trim)); -end; - -procedure TMyController.OnAfterAction(Context: TWebContext; const AActionName: string); -begin - { Executed after each action } - inherited; -end; - -procedure TMyController.OnBeforeAction(Context: TWebContext; const AActionName: string; var Handled: Boolean); -begin - { Executed before each action - if handled is true (or an exception is raised) the actual - action will not be called } - inherited; -end; - -// Sample CRUD Actions for a "Customer" entity -procedure TMyController.GetCustomers; -begin - // todo: render a list of customers -end; - -procedure TMyController.GetCustomer(id: Integer); -begin - // todo: render the customer by id -end; - -procedure TMyController.CreateCustomer; - -begin - // todo: create a new customer -end; - -procedure TMyController.UpdateCustomer(id: Integer); -begin - // todo: update customer by id -end; - -procedure TMyController.DeleteCustomer(id: Integer); -begin - // todo: delete customer by id + Render( + ObjectDict().Add('data', StrDict.Add('message', Dict['hello'])) + ) end; end. diff --git a/samples/middleware_cors/ProjectGroup.groupproj b/samples/middleware_cors/ProjectGroup.groupproj new file mode 100644 index 00000000..1b15a52f --- /dev/null +++ b/samples/middleware_cors/ProjectGroup.groupproj @@ -0,0 +1,48 @@ + + + {9F8DA910-24A1-4497-AAB9-7BDE0D4186C2} + + + + + + + + + + + Default.Personality.12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/middleware_cors/SPARedirectController.pas b/samples/middleware_cors/SPARedirectController.pas deleted file mode 100644 index 347c9f05..00000000 --- a/samples/middleware_cors/SPARedirectController.pas +++ /dev/null @@ -1,29 +0,0 @@ -unit SPARedirectController; - -interface - -uses - MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons; - -type - - [MVCPath] - TSPARedirectController = class(TMVCController) - public - [MVCPath('/')] - [MVCProduces(TMVCMediaType.TEXT_HTML)] - [MVCHTTPMethod([httpGET])] - procedure Index; - end; - -implementation - -uses - System.SysUtils, MVCFramework.Logger, System.StrUtils; - -procedure TSPARedirectController.Index; -begin - Redirect('/static'); -end; - -end. diff --git a/samples/middleware_cors/SimpleWebServer/SimpleWebServer.dpr b/samples/middleware_cors/SimpleWebServer/SimpleWebServer.dpr new file mode 100644 index 00000000..ecf31502 --- /dev/null +++ b/samples/middleware_cors/SimpleWebServer/SimpleWebServer.dpr @@ -0,0 +1,90 @@ +program SimpleWebServer; + +{$APPTYPE CONSOLE} + +uses + System.SysUtils, + WinAPI.ShellAPI, + MVCFramework, + MVCFramework.Logger, + MVCFramework.DotEnv, + MVCFramework.Commons, + MVCFramework.Signal, + Web.ReqMulti, + Web.WebReq, + Web.WebBroker, + IdContext, + IdHTTPWebBrokerBridge, + WebModuleU in 'WebModuleU.pas', Winapi.Windows {MyWebModule: TWebModule}; + +{$R *.res} + + +procedure RunServer(APort: Integer); +var + LServer: TIdHTTPWebBrokerBridge; +begin + Writeln('** DMVCFramework Server ** build ' + DMVCFRAMEWORK_VERSION); + LServer := TIdHTTPWebBrokerBridge.Create(nil); + try + LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication; + LServer.DefaultPort := APort; + LServer.KeepAlive := True; + LServer.MaxConnections := dotEnv.Env('dmvc.webbroker.max_connections', 0); + LServer.ListenQueue := dotEnv.Env('dmvc.indy.listen_queue', 500); + + LServer.Active := True; + + { Comment the next line to avoid the default browser startup } +{$IFDEF MSWINDOWS} + ShellExecute(0, 'open', PChar('http://localhost:' + inttostr(APort)), nil, nil, SW_SHOWMAXIMIZED); +{$ENDIF} + + WriteLn('Simple Web Server'); + WriteLn('Listening on port ', APort); + Write('CTRL+C to shutdown the server'); + WaitForTerminationSignal; + EnterInShutdownState; + LServer.Active := False; + finally + LServer.Free; + end; +end; + +begin + { Enable ReportMemoryLeaksOnShutdown during debug } + // ReportMemoryLeaksOnShutdown := True; + IsMultiThread := True; + + // DMVCFramework Specific Configuration + // When MVCSerializeNulls = True empty nullables and nil are serialized as json null. + // When MVCSerializeNulls = False empty nullables and nil are not serialized at all. + MVCSerializeNulls := True; + + try + if WebRequestHandler <> nil then + WebRequestHandler.WebModuleClass := WebModuleClass; + + dotEnvConfigure( + function: IMVCDotEnv + begin + Result := NewDotEnv + .WithStrategy(TMVCDotEnvPriority.FileThenEnv) + //if available, by default, loads default environment (.env) + .UseProfile('test') //if available loads the test environment (.env.test) + .UseProfile('prod') //if available loads the prod environment (.env.prod) + .UseLogger(procedure(LogItem: String) + begin + LogW('dotEnv: ' + LogItem); + end) + .Build(); //uses the executable folder to look for .env* files + end); + + WebRequestHandlerProc.MaxConnections := dotEnv.Env('dmvc.handler.max_connections', 1024); + + RunServer(dotEnv.Env('dmvc.server.port', 9090)); + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end; +end. diff --git a/samples/middleware_cors/SimpleWebServer/SimpleWebServer.dproj b/samples/middleware_cors/SimpleWebServer/SimpleWebServer.dproj new file mode 100644 index 00000000..a91e14bf --- /dev/null +++ b/samples/middleware_cors/SimpleWebServer/SimpleWebServer.dproj @@ -0,0 +1,909 @@ + + + {1553C606-62E3-4D67-8E5B-3440886F90A9} + 19.5 + None + True + Debug + Win32 + 1 + Console + SimpleWebServer.dpr + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + .\$(Platform)\$(Config) + ..\bin + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + true + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\delphi_PROJECTICNS.icns + $(DMVC);$(DCC_UnitSearchPath) + VCL;$(DCC_Framework) + SimpleWebServer + 1040 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + + + fmx;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;bindcompfmx;ibmonitor;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;Python;inet;DataSnapCommon;fmxase;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;Skia.Package.FMX;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;ibxbindings;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;ibxpress;dsnap;CloudService;FMXTee;DataSnapNativeClient;PythonFmx;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) + activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar + + + fmx;DbxCommonDriver;bindengine;IndyIPCommon;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;FmxTeeUI;bindcompfmx;ibmonitor;FireDACSqliteDriver;DbxClientDriver;soapmidas;fmxFireDAC;dbexpress;Python;inet;DataSnapCommon;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;Skia.Package.FMX;CustomIPTransport;DBXInterBaseDriver;IndySystem;RadiantShapesFmx;ibxbindings;bindcomp;FireDACCommon;IndyCore;RESTBackendComponents;bindcompdbx;rtl;RESTComponents;DBXSqliteDriver;IndyIPServer;dsnapxml;DataSnapClient;DataSnapProviderClient;DataSnapFireDAC;emsclientfiredac;FireDAC;FireDACDSDriver;xmlrtl;tethering;ibxpress;dsnap;CloudService;FMXTee;DataSnapNativeClient;PythonFmx;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) + activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar + + + DataSnapServer;fmx;emshosting;DbxCommonDriver;bindengine;FireDACCommonODBC;emsclient;FireDACCommonDriver;IndyProtocols;Skia.Package.RTL;RadiantShapesFmx_Design;dbxcds;emsedge;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;dbexpress;FireDACInfxDriver;Python;inet;DataSnapCommon;dbrtl;FireDACOracleDriver;Skia.Package.FMX;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;dsnapxml;DataSnapClient;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;xmlrtl;dsnap;CloudService;FireDACDb2Driver;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) + + + RaizeComponentsVcl;JvNet;vclwinx;DataSnapServer;FixInsight_11;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;frxe28;frxTee28;bindcompvclwinx;Prometheus.Client.Core;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;JvBands;inetdb;JvAppFrm;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;JclVcl;SVGIconImageListFMX;vclactnband;TeeUI;fmxFireDAC;dbexpress;Jcl;JvManagedThreads;FireDACInfxDriver;Python;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;JvPascalInterpreter;PythonVcl;vcltouch;fmxase;frx28;JvPluginSystem;DBXOdbcDriver;DzHTMLText_FMX;dbrtl;JvDB;FireDACDBXDriver;FireDACOracleDriver;ComPortDrv;fmxdae;TeeDB;Skia.Package.FMX;JvTimeFramework;FireDACMSAccDriver;JvCustom;CustomIPTransport;FireDACMSSQLDriver;JvSystem;SVGIconPackage;DataSnapIndy10ServerTransport;JclDeveloperTools;JvControls;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;JvCrypt;FireDACMongoDBDriver;JvJans;JvMM;IndySystem;JvWizards;frxDB28;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;JvGlobus;vcldb;ibxbindings;IconFontsImageList;JclContainers;SynEditDR;JvPageComps;vclFireDAC;JvCore;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;dmvcframeworkDT;bindcompdbx;DzHTMLText_VCL;rtl;FireDACMySQLDriver;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;JvDotNetCtrls;JvHMI;DBXSybaseASEDriver;JvRuntimeDesign;DBXDb2Driver;JvXPCtrls;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;JvStdCtrls;ibxpress;JvDlgs;JvDocking;bindcompvcl;dsnap;JvPrintPreview;JvCmp;dmvcframeworkRT;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;IconFontsImageListFMX;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;PythonFmx;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + + + RaizeComponentsVcl;vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;RadiantShapesFmx_Design;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;SVGIconImageListFMX;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;Python;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;PythonVcl;vcltouch;fmxase;DBXOdbcDriver;DzHTMLText_FMX;dbrtl;FireDACDBXDriver;FireDACOracleDriver;ComPortDrv;fmxdae;TeeDB;Skia.Package.FMX;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;SVGIconPackage;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;Skia.Package.VCL;vcldb;ibxbindings;SynEditDR;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;DzHTMLText_VCL;rtl;FireDACMySQLDriver;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;PythonFmx;DatasnapConnectorsFreePascal;soaprtl;SVGIconImageList;soapserver;FireDACIBDriver;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + true + true + + + false + 1033 + (None) + none + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + + + + Delphi.Personality.12 + Console + + + + SimpleWebServer.dpr + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + true + + + + + true + + + + + true + + + + + SimpleWebServer.exe + true + + + + + 1 + + + 0 + + + + + classes + 64 + + + classes + 64 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + 1 + + + 0 + + + + + 1 + .framework + + + 1 + .framework + + + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + False + False + False + True + False + + + 12 + + + + + diff --git a/samples/middleware_cors/SimpleWebServer/WebModuleU.dfm b/samples/middleware_cors/SimpleWebServer/WebModuleU.dfm new file mode 100644 index 00000000..02d66b97 --- /dev/null +++ b/samples/middleware_cors/SimpleWebServer/WebModuleU.dfm @@ -0,0 +1,7 @@ +object MyWebModule: TMyWebModule + OnCreate = WebModuleCreate + OnDestroy = WebModuleDestroy + Actions = <> + Height = 230 + Width = 415 +end diff --git a/samples/middleware_cors/SimpleWebServer/WebModuleU.pas b/samples/middleware_cors/SimpleWebServer/WebModuleU.pas new file mode 100644 index 00000000..90af30be --- /dev/null +++ b/samples/middleware_cors/SimpleWebServer/WebModuleU.pas @@ -0,0 +1,125 @@ +unit WebModuleU; + +interface + +uses + System.SysUtils, + System.Classes, + Web.HTTPApp, + MVCFramework; + +type + TMyWebModule = class(TWebModule) + procedure WebModuleCreate(Sender: TObject); + procedure WebModuleDestroy(Sender: TObject); + private + FMVC: TMVCEngine; + public + { Public declarations } + end; + +var + WebModuleClass: TComponentClass = TMyWebModule; + +implementation + +{$R *.dfm} + +uses + System.IOUtils, + MVCFramework.Commons, + MVCFramework.Middleware.ActiveRecord, + MVCFramework.Middleware.StaticFiles, + MVCFramework.Middleware.Analytics, + MVCFramework.Middleware.Redirect, + MVCFramework.Middleware.Trace, + MVCFramework.Middleware.CORS, + MVCFramework.Middleware.ETag, + MVCFramework.Middleware.Compression; + +procedure TMyWebModule.WebModuleCreate(Sender: TObject); +begin + FMVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + Config.dotEnv := dotEnv; + // session timeout (0 means session cookie) + Config[TMVCConfigKey.SessionTimeout] := dotEnv.Env('dmvc.session_timeout', '0'); + //default content-type + Config[TMVCConfigKey.DefaultContentType] := dotEnv.Env('dmvc.default.content_type', TMVCConstants.DEFAULT_CONTENT_TYPE); + //default content charset + Config[TMVCConfigKey.DefaultContentCharset] := dotEnv.Env('dmvc.default.content_charset', TMVCConstants.DEFAULT_CONTENT_CHARSET); + //unhandled actions are permitted? + Config[TMVCConfigKey.AllowUnhandledAction] := dotEnv.Env('dmvc.allow_unhandled_actions', 'false'); + //enables or not system controllers loading (available only from localhost requests) + Config[TMVCConfigKey.LoadSystemControllers] := dotEnv.Env('dmvc.load_system_controllers', 'true'); + //default view file extension + Config[TMVCConfigKey.DefaultViewFileExtension] := dotEnv.Env('dmvc.default.view_file_extension', 'html'); + //view path + Config[TMVCConfigKey.ViewPath] := dotEnv.Env('dmvc.view_path', 'templates'); + //Max Record Count for automatic Entities CRUD + Config[TMVCConfigKey.MaxEntitiesRecordCount] := dotEnv.Env('dmvc.max_entities_record_count', IntToStr(TMVCConstants.MAX_RECORD_COUNT)); + //Enable Server Signature in response + Config[TMVCConfigKey.ExposeServerSignature] := dotEnv.Env('dmvc.expose_server_signature', 'false'); + //Enable X-Powered-By Header in response + Config[TMVCConfigKey.ExposeXPoweredBy] := dotEnv.Env('dmvc.expose_x_powered_by', 'true'); + // Max request size in bytes + Config[TMVCConfigKey.MaxRequestSize] := dotEnv.Env('dmvc.max_request_size', IntToStr(TMVCConstants.DEFAULT_MAX_REQUEST_SIZE)); + end); + + // Analytics middleware generates a csv log, useful to do traffic analysis + //FMVC.AddMiddleware(TMVCAnalyticsMiddleware.Create(GetAnalyticsDefaultLogger)); + + // The folder mapped as documentroot for TMVCStaticFilesMiddleware must exists! + FMVC.AddMiddleware( + TMVCStaticFilesMiddleware.Create( + '/static', + TPath.Combine(ExtractFilePath(GetModuleName(HInstance)), 'www'))); + + FMVC.AddMiddleware(TMVCRedirectMiddleware.Create(['/'], '/static')); + + // Trace middlewares produces a much detailed log for debug purposes + //FMVC.AddMiddleware(TMVCTraceMiddleware.Create); + + // CORS middleware handles... well, CORS + //FMVC.AddMiddleware(TMVCCORSMiddleware.Create); + + // Simplifies TMVCActiveRecord connection definition + { + FMVC.AddMiddleware(TMVCActiveRecordMiddleware.Create( + dotEnv.Env('firedac.connection_definition_name', 'MyConnDef'), + dotEnv.Env('firedac.connection_definitions_filename', 'FDConnectionDefs.ini') + )); + } + + + // 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); + + + + { + FMVC.OnWebContextCreate( + procedure(const Context: TWebContext) + begin + // Initialize services to make them accessibile from Context + // Context.CustomIntfObject := TMyService.Create; + end); + + FMVC.OnWebContextDestroy( + procedure(const Context: TWebContext) + begin + //Cleanup services, if needed + end); + } +end; + +procedure TMyWebModule.WebModuleDestroy(Sender: TObject); +begin + FMVC.Free; +end; + +end. diff --git a/samples/middleware_cors/WebModuleU.pas b/samples/middleware_cors/WebModuleU.pas index 10524579..7e18b01d 100644 --- a/samples/middleware_cors/WebModuleU.pas +++ b/samples/middleware_cors/WebModuleU.pas @@ -32,9 +32,9 @@ uses System.IOUtils, MVCFramework.Commons, MVCFramework.Middleware.StaticFiles, + MVCFramework.Middleware.Redirect, MVCFramework.Middleware.Compression, - MVCFramework.Middleware.CORS, - SPARedirectController; + MVCFramework.Middleware.CORS; procedure TMyWebModule.WebModuleCreate(Sender: TObject); begin @@ -62,20 +62,14 @@ begin Config[TMVCConfigKey.LoadSystemControllers] := 'false'; end); FMVC - .AddController(TMyController) - .AddController(TSPARedirectController); + .AddController(TMyController); - // Required to enable serving of static files - FMVC.AddMiddleware(TMVCCORSMiddleware.Create); - // Required to enable serving of static files - FMVC.AddMiddleware(TMVCStaticFilesMiddleware.Create( - '/static', - TPath.Combine(ExtractFilePath(GetModuleName(HInstance)), 'www')) - ); + { // Allows all origins -> * } + //FMVC.AddMiddleware(TMVCCORSMiddleware.Create); - // To enable compression (deflate, gzip) just add this middleware as the last one - FMVC.AddMiddleware(TMVCCompressionMiddleware.Create); + { // Allows all origins -> * } + FMVC.AddMiddleware(TMVCCORSMiddleware.Create('https://anotherserver.com,http://localhost:9090')); end; procedure TMyWebModule.WebModuleDestroy(Sender: TObject); diff --git a/samples/middleware_cors/bin/www/index.html b/samples/middleware_cors/bin/www/index.html index 1b363e0f..903df5db 100644 --- a/samples/middleware_cors/bin/www/index.html +++ b/samples/middleware_cors/bin/www/index.html @@ -1 +1,29 @@ -INDEX FILE IN WWW \ No newline at end of file + + + + + + + DMVCFramework CORS Sample + + + + + +
+ + + + \ No newline at end of file diff --git a/samples/middleware_cors/middleware_cors.dpr b/samples/middleware_cors/middleware_cors.dpr index 99674c13..1bbfc40a 100644 --- a/samples/middleware_cors/middleware_cors.dpr +++ b/samples/middleware_cors/middleware_cors.dpr @@ -8,10 +8,10 @@ uses MVCFramework, MVCFramework.Logger, MVCFramework.Commons, -{$IFDEF MSWINDOWS} + {$IFDEF MSWINDOWS} Winapi.Windows, Winapi.ShellAPI, -{$ENDIF} + {$ENDIF } MVCFramework.Signal, Web.ReqMulti, Web.WebReq, @@ -19,8 +19,7 @@ uses IdContext, IdHTTPWebBrokerBridge, MainControllerU in 'MainControllerU.pas', - WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule} , - SPARedirectController in 'SPARedirectController.pas'; + WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule}; {$R *.res} @@ -35,25 +34,18 @@ begin try LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication; LServer.DefaultPort := APort; - - { more info about MaxConnections - http://www.indyproject.org/docsite/html/frames.html?frmname=topic&frmfile=TIdCustomTCPServer_MaxConnections.html } LServer.MaxConnections := 0; - - { more info about ListenQueue - http://www.indyproject.org/docsite/html/frames.html?frmname=topic&frmfile=TIdCustomTCPServer_ListenQueue.html } LServer.ListenQueue := 200; - { Comment the next line to avoid the default browser startup } -{$IFDEF MSWINDOWS} - //ShellExecute(0, 'open', PChar('http://localhost:' + inttostr(APort)), nil, nil, SW_SHOWMAXIMIZED); -{$ENDIF} { required if you use JWT middleware } LServer.OnParseAuthentication := TMVCParseAuthentication.OnParseAuthentication; LServer.Active := True; - Writeln('CTRL+C to shutdown the server'); + WriteLn('Middleware CORS Sample'); + WriteLn('Listening on port ', APort); + Write('CTRL+C to shutdown the server'); WaitForTerminationSignal; EnterInShutdownState; + LServer.Active := False; finally LServer.Free; end; diff --git a/samples/middleware_cors/middleware_cors.dproj b/samples/middleware_cors/middleware_cors.dproj index f09e2eab..7e6ad52e 100644 --- a/samples/middleware_cors/middleware_cors.dproj +++ b/samples/middleware_cors/middleware_cors.dproj @@ -122,7 +122,6 @@
MyWebModule
TWebModule
- Base diff --git a/sources/MVCFramework.Middleware.CORS.pas b/sources/MVCFramework.Middleware.CORS.pas index a844f2c8..cb129e46 100644 --- a/sources/MVCFramework.Middleware.CORS.pas +++ b/sources/MVCFramework.Middleware.CORS.pas @@ -61,13 +61,16 @@ type end; TMVCCORSMiddleware = class(TInterfacedObject, IMVCMiddleware) - private + strict protected FAllowedOriginURL: string; + FAllowedOriginURLs: TArray; FAllowsCredentials: Boolean; FAllowsMethods: string; FExposeHeaders: string; FAllowsHeaders: string; protected + function GetAllowedOriginURL(AContext: TWebContext): String; virtual; + procedure OnBeforeRouting( AContext: TWebContext; var AHandled: Boolean @@ -92,7 +95,7 @@ type public constructor Create( - const AAllowedOriginURL: string = TMVCCORSDefaults.ALLOWS_ORIGIN_URL; + const AAllowedOriginURLs: string = TMVCCORSDefaults.ALLOWS_ORIGIN_URL; const AAllowsCredentials: Boolean = TMVCCORSDefaults.ALLOWS_CREDENTIALS; const AExposeHeaders: String = TMVCCORSDefaults.EXPOSE_HEADERS; const AAllowsHeaders: String = TMVCCORSDefaults.ALLOWS_HEADERS; @@ -104,10 +107,13 @@ type implementation +uses + System.SysUtils; + { TMVCCORSMiddleware } constructor TMVCCORSMiddleware.Create( - const AAllowedOriginURL: string; + const AAllowedOriginURLs: string; const AAllowsCredentials: Boolean; const AExposeHeaders: String; const AAllowsHeaders: String; @@ -115,13 +121,32 @@ constructor TMVCCORSMiddleware.Create( ); begin inherited Create; - FAllowedOriginURL := AAllowedOriginURL; FAllowsCredentials := AAllowsCredentials; FExposeHeaders := AExposeHeaders; FAllowsHeaders := AAllowsHeaders; FAllowsMethods := AAllowsMethods; end; +function TMVCCORSMiddleware.GetAllowedOriginURL(AContext: TWebContext): String; +var + lRequestOrigin: string; + lAllowed: String; +begin + Result := ''; + lRequestOrigin := AContext.Request.Headers['Origin']; + if lRequestOrigin <> '' then + begin + for var I := Low(FAllowedOriginURLs) to High(FAllowedOriginURLs) do + begin + lAllowed := FAllowedOriginURLs[I].Trim; + if SameText(lRequestOrigin, lAllowed) or (lAllowed = '*') then + begin + Exit(lAllowed); + end; + end; + end; +end; + procedure TMVCCORSMiddleware.OnAfterControllerAction( AContext: TWebContext; const AControllerQualifiedClassName: string; const AActionName: string; @@ -144,7 +169,7 @@ end; procedure TMVCCORSMiddleware.OnBeforeRouting(AContext: TWebContext; var AHandled: Boolean); begin - AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Origin'] := FAllowedOriginURL; + AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Origin'] := GetAllowedOriginURL(AContext); AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Methods'] := FAllowsMethods; AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Headers'] := FAllowsHeaders; From 1b9abb39d60f7b2de1966f22403442bef3362dce Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Tue, 15 Aug 2023 21:31:22 +0200 Subject: [PATCH 31/31] Updated README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b71cebb2..5541abe8 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,8 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma - 🐞 FIX [Issue 667](https://github.com/danieleteti/delphimvcframework/issues/667) +- 🐞 FIX [Issue 680](https://github.com/danieleteti/delphimvcframework/issues/680) + - 🐞 FIX Wrong comparison in checks for ro/RW/PK fields in `TMVCActiveRecord` - 🐞 FIX wrong default initialization for JWT (thanks to Flavio Basile) @@ -251,6 +253,8 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma - ⚡ Better error message in case of serialization of `TArray` +- ⚡ Improved CORS handling - [Issue 679](https://github.com/danieleteti/delphimvcframework/issues/679) (Thanks to [David Moorhouse](https://github.com/fastbike)) + - ⚡ Improved serialization of `TObjectList` (however `ObjectDict` is still the preferred way to serialize multiple datasets). - ⚡ Added static method for easier cloning of FireDAC dataset into `TFDMemTable`.