From 78c797743b3a6430495c11cd7c17ae42fffed95e Mon Sep 17 00:00:00 2001 From: Brayden Tan Date: Thu, 21 Nov 2024 09:29:05 +0800 Subject: [PATCH 1/5] [twgit] Init feature 'feature-display-change-queue-records-in-admin'. From c488116dd174ebceddc880acfe89503408f3b58c Mon Sep 17 00:00:00 2001 From: Brayden Tan Date: Thu, 21 Nov 2024 10:46:43 +0800 Subject: [PATCH 2/5] Display change queue records in admin --- handlers/admin/DataApiManager.cfc | 34 ++++++++++++++- handlers/admin/datamanager/data_api_queue.cfc | 36 ++++++++++++++++ .../content/DataApiQueueObjectName.cfc | 8 ++++ i18n/cms.properties | 7 +++ .../preside-objects/data_api_queue.properties | 4 +- preside-objects/data_api_queue.cfc | 6 ++- views/admin/apiManager/configureAuth.cfm | 13 ++++++ views/admin/apiManager/index.cfm | 18 ++++++++ views/admin/dataApiManager/queueListing.cfm | 43 +++++++++++++++++++ 9 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 handlers/admin/datamanager/data_api_queue.cfc create mode 100644 handlers/renderers/content/DataApiQueueObjectName.cfc create mode 100644 i18n/cms.properties create mode 100644 views/admin/apiManager/configureAuth.cfm create mode 100644 views/admin/apiManager/index.cfm create mode 100644 views/admin/dataApiManager/queueListing.cfm diff --git a/handlers/admin/DataApiManager.cfc b/handlers/admin/DataApiManager.cfc index 798edc4..1728ca8 100644 --- a/handlers/admin/DataApiManager.cfc +++ b/handlers/admin/DataApiManager.cfc @@ -1,7 +1,8 @@ component extends="preside.system.base.AdminHandler" { property name="dataApiUserConfigurationService" inject="dataApiUserConfigurationService"; - property name="messagebox" inject="messagebox@cbmessagebox"; + property name="dataApiConfig" inject="coldbox:setting:rest.apis"; + property name="messagebox" inject="messagebox@cbmessagebox"; function prehandler( event, rc, prc ) { super.preHandler( argumentCollection = arguments ); @@ -186,6 +187,37 @@ component extends="preside.system.base.AdminHandler" { } + public void function queueListing( event, rc, prc ) { + if ( Len( Trim( rc.apiRoute ?: "" ) ) && StructKeyExists( dataApiConfig, rc.apiRoute ) ) { + prc.filterNamespace = dataApiConfig[ rc.apiRoute ].dataApiNamespace ?: ""; + + event.addAdminBreadCrumb( + title = translateResource( uri="cms:apiManager.configureauth.page.breadcrumbTitle", data=[ rc.apiRoute ] ) + , link = event.buildAdminLink( linkTo = "apimanager.configureAuth", queryString="id=#rc.apiRoute#" ) + ); + } + + event.addAdminBreadCrumb( + title = translateResource( "cms:apiQueueListing.breadcrumbTitle" ) + , link = event.buildAdminLink( linkTo="dataApiManager.queueListing" ) + ); + + prc.pageIcon = "fa-stream"; + prc.pageTitle = translateResource( "cms:apiQueueListing.page.title" ); + prc.pageSubtitle = translateResource( "cms:apiQueueListing.page.subtitle" ); + + prc.activeRestUser = rc.restUser ?: ""; + prc.queueRestUsers = getPresideObject( "data_api_user_settings" ).selectData( + groupBy = "user.name" + , filter = "subscribe_to_deletes = :trueValue OR subscribe_to_updates = :trueValue OR subscribe_to_inserts = :trueValue" + , filterParams = { trueValue={ type="cf_sql_bit", value=true } } + , selectFields = [ "user.id", "user.name" ] + ); + + if ( isEmptyString( prc.activeRestUser ) ) { + prc.activeRestUser = prc.queueRestUsers.id ?: ""; + } + } private boolean function _checkPermissions( required any event, required string key, boolean throwOnError=true ) { var hasPermission = hasCmsPermission( "apiManager." & arguments.key ); diff --git a/handlers/admin/datamanager/data_api_queue.cfc b/handlers/admin/datamanager/data_api_queue.cfc new file mode 100644 index 0000000..96e6a43 --- /dev/null +++ b/handlers/admin/datamanager/data_api_queue.cfc @@ -0,0 +1,36 @@ +component { + property name="loginService" inject="LoginService"; + + private string function getAdditionalQueryStringForBuildAjaxListingLink( event, rc, prc, args={} ) { + var qs = []; + if ( Len( Trim( prc.activeRestUser ?: "" ) ) ) { + ArrayAppend( qs, "subscriber=#prc.activeRestUser#" ); + } + if ( StructKeyExists( prc, "filterNamespace" ) ) { + ArrayAppend( qs, "namespace=#prc.filterNamespace#" ); + } + return ArrayToList( qs, "&" ); + } + private void function preFetchRecordsForGridListing( event, rc, prc, args={} ) { + args.extraFilters = args.extraFilters ?: []; + + if ( Len( Trim( rc.subscriber ?: "" ) ) ) { + ArrayAppend( args.extraFilters, { filter={ subscriber=rc.subscriber } } ); + } + if ( StructKeyExists( rc, "namespace" ) ) { + ArrayAppend( args.extraFilters, { filter={ namespace=rc.namespace } } ); + } + } + + private void function extraRecordActionsForGridListing( event, rc, prc, args={} ) { + args.actions = args.actions ?: []; + + if ( Len( Trim( args.record.record_id ?: "" ) ) && Len( Trim( args.record.object_name ?: "" ) ) ) { + for ( var action in args.actions ) { + if ( ( action.contextKey ?: "" ) == "v" ) { + action.link = event.buildAdminLink( objectName=args.record.object_name, recordId=args.record.record_id ); + } + } + } + } +} \ No newline at end of file diff --git a/handlers/renderers/content/DataApiQueueObjectName.cfc b/handlers/renderers/content/DataApiQueueObjectName.cfc new file mode 100644 index 0000000..1d21821 --- /dev/null +++ b/handlers/renderers/content/DataApiQueueObjectName.cfc @@ -0,0 +1,8 @@ +component { + + private string function default( event, rc, prc, args={} ){ + var objName = args.data ?: ""; + + return Len( Trim( objName ) ) ? "#translateResource( uri="preside-objects.#objName#:title", defaultValue=objName )# (#objName#)" : ""; + } +} \ No newline at end of file diff --git a/i18n/cms.properties b/i18n/cms.properties new file mode 100644 index 0000000..02043b6 --- /dev/null +++ b/i18n/cms.properties @@ -0,0 +1,7 @@ +apiQueueListing=Data API queue listing +apiQueueListing.breadcrumbTitle=API queue listing +apiQueueListing.iconclass=fa-stream +apiQueueListing.btn=Queue listing +apiQueueListing.page.title=Data API queue listing +apiQueueListing.page.subtitle=Manage API queue records +apiQueueListing.alert.no.queue.user.msg=There are no rest user subscribe to API queue in your application. \ No newline at end of file diff --git a/i18n/preside-objects/data_api_queue.properties b/i18n/preside-objects/data_api_queue.properties index 5e94527..9304108 100644 --- a/i18n/preside-objects/data_api_queue.properties +++ b/i18n/preside-objects/data_api_queue.properties @@ -9,4 +9,6 @@ field.record_id.title=Record ID field.operation.title=Operation field.order_number.title=Order number field.subscriber.title=Subscriber -field.data.title=Data \ No newline at end of file +field.data.title=Data +field.is_checked_out.title=Checked out? +field.check_out_date.title=Check out date \ No newline at end of file diff --git a/preside-objects/data_api_queue.cfc b/preside-objects/data_api_queue.cfc index 70248f0..bcbfbab 100644 --- a/preside-objects/data_api_queue.cfc +++ b/preside-objects/data_api_queue.cfc @@ -3,9 +3,13 @@ * @nolabel true * @noDateModified true * @feature dataApiQueue + * + * @dataManagerEnabled true + * @datamanagerAllowedOperations read + * @datamanagerDefaultSortOrder order_number desc */ component { - property name="object_name" type="string" dbtype="varchar" maxlength=100 required=true indexes="object_name"; + property name="object_name" type="string" dbtype="varchar" maxlength=100 required=true indexes="object_name" renderer="DataApiQueueObjectName"; property name="namespace" type="string" dbtype="varchar" maxlength=50 required=false indexes="namespace"; property name="queue_name" type="string" dbtype="varchar" maxlength=50 required=false indexes="queuename"; property name="record_id" type="string" dbtype="varchar" maxlength=100 required=true indexes="record_id"; diff --git a/views/admin/apiManager/configureAuth.cfm b/views/admin/apiManager/configureAuth.cfm new file mode 100644 index 0000000..379123d --- /dev/null +++ b/views/admin/apiManager/configureAuth.cfm @@ -0,0 +1,13 @@ + + + + + + + #( prc.body ?: "" )# + \ No newline at end of file diff --git a/views/admin/apiManager/index.cfm b/views/admin/apiManager/index.cfm new file mode 100644 index 0000000..e85b504 --- /dev/null +++ b/views/admin/apiManager/index.cfm @@ -0,0 +1,18 @@ + + + apis = prc.apis ?: []; + configLinkBase = prc.configLinkBase ?: ""; + + + + + + + + + \ No newline at end of file diff --git a/views/admin/dataApiManager/queueListing.cfm b/views/admin/dataApiManager/queueListing.cfm new file mode 100644 index 0000000..4fd345f --- /dev/null +++ b/views/admin/dataApiManager/queueListing.cfm @@ -0,0 +1,43 @@ + + queueRestUsers = prc.queueRestUsers ?: QueryNew( "" ); + activeRestUser = Len( Trim( prc.activeRestUser ?: "" ) ) ? prc.activeRestUser : ( queueRestUsers.id ?: "" ); + apiRoute = rc.apiRoute ?: ""; + gridFields = prc.gridFields ?: [ "queue_name", "object_name", "record_id", "operation", "order_number" ]; + + if ( isEmptyString( apiRoute ) && !ArrayFindNoCase( gridFields, "namespace" ) ) { + ArrayPrepend( gridFields, "namespace" ) + } + + + + +

+ + #translateResource( "cms:apiQueueListing.alert.no.queue.user.msg" )# +

+ +
+ + +
+
+ #objectDataTable( objectName="data_api_queue", args={ + gridFields = gridFields + , allowDataExport = false + , useMultiActions = false + , compact = true + } )# +
+
+
+
+
\ No newline at end of file From e2d80746ad6fa0f3bca7a0883857d737a7afb431 Mon Sep 17 00:00:00 2001 From: Brayden Tan Date: Thu, 21 Nov 2024 10:54:30 +0800 Subject: [PATCH 3/5] filter by namespace when available --- handlers/admin/DataApiManager.cfc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/handlers/admin/DataApiManager.cfc b/handlers/admin/DataApiManager.cfc index 1728ca8..6f0dab2 100644 --- a/handlers/admin/DataApiManager.cfc +++ b/handlers/admin/DataApiManager.cfc @@ -188,9 +188,15 @@ component extends="preside.system.base.AdminHandler" { } public void function queueListing( event, rc, prc ) { + var restUserQueryFilter = "subscribe_to_deletes = :trueValue OR subscribe_to_updates = :trueValue OR subscribe_to_inserts = :trueValue"; + var restUserQueryParams = { trueValue={ type="cf_sql_bit", value=true } }; + if ( Len( Trim( rc.apiRoute ?: "" ) ) && StructKeyExists( dataApiConfig, rc.apiRoute ) ) { prc.filterNamespace = dataApiConfig[ rc.apiRoute ].dataApiNamespace ?: ""; + restUserQueryFilter = "( #restUserQueryFilter# ) AND namespace = :namespace"; + restUserQueryParams.namespace = prc.filterNamespace; + event.addAdminBreadCrumb( title = translateResource( uri="cms:apiManager.configureauth.page.breadcrumbTitle", data=[ rc.apiRoute ] ) , link = event.buildAdminLink( linkTo = "apimanager.configureAuth", queryString="id=#rc.apiRoute#" ) @@ -209,8 +215,8 @@ component extends="preside.system.base.AdminHandler" { prc.activeRestUser = rc.restUser ?: ""; prc.queueRestUsers = getPresideObject( "data_api_user_settings" ).selectData( groupBy = "user.name" - , filter = "subscribe_to_deletes = :trueValue OR subscribe_to_updates = :trueValue OR subscribe_to_inserts = :trueValue" - , filterParams = { trueValue={ type="cf_sql_bit", value=true } } + , filter = restUserQueryFilter + , filterParams = restUserQueryParams , selectFields = [ "user.id", "user.name" ] ); From 9206065c2d5625c12e30170243d0a728bd17a454 Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Thu, 21 Nov 2024 10:58:47 +0000 Subject: [PATCH 4/5] [twgit] Init release 'release-3.6.0'. From dfa220b97f99f89aa8a5bae577f7f2c950261761 Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Mon, 25 Nov 2024 15:15:23 +0000 Subject: [PATCH 5/5] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d7e5d..5e18453 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v3.6.0 + +* Added a UI to show records in the DATA API change queue per subscribed API client + ## v3.5.15 * Non string renderers: respect returned data when it is an empty array or struct for rendering in results