diff --git a/ckanext/recombinant/assets/css/recombinant.css b/ckanext/recombinant/assets/css/recombinant.css new file mode 100644 index 0000000..b7d324e --- /dev/null +++ b/ckanext/recombinant/assets/css/recombinant.css @@ -0,0 +1,38 @@ +#api-access-accordion figure{ + display: none; +} +#api-access-accordion figure.python{ + display: none; +} +/* Default cURL display */ +#api-access-accordion figure.curl{ + display: block; +} +#api-access-accordion figure.powershell{ + display: none; +} +#api-access-example-code-control label::after{ + content: none !important; +} +#api-access-example-code-control input[type="radio"]{ + cursor: pointer !important; +} +#api-access-accordion figure{ + margin-bottom: 12px !important; +} +#api-access-accordion pre{ + margin-bottom: 0 !important; + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} +#api-access-accordion figure figcaption{ + padding: 4px 8px; + background-color: #335075; + color: white; + font-weight: 700 !important; + font-size: 14px; + line-height: 1.5 !important; + border-bottom-left-radius: 4px !important; + border-bottom-right-radius: 4px !important; + text-align: right !important; +} diff --git a/ckanext/recombinant/assets/js/code_block_buttons.js b/ckanext/recombinant/assets/js/code_block_buttons.js new file mode 100644 index 0000000..cbe52f2 --- /dev/null +++ b/ckanext/recombinant/assets/js/code_block_buttons.js @@ -0,0 +1,76 @@ +window.addEventListener('load', function(){ + $(document).ready(function() { + + // Code example switching + let codeExampleControl = $('#api-access-example-code-control'); + let codeBlocks = $('#api-access-accordion').find('figure'); + + if( codeExampleControl.length > 0 ){ + + let controlButtons = $(codeExampleControl).find('input[name="api-access-example-code"]'); + + if( controlButtons.length > 0 ){ + + $(controlButtons).on('change', function(_event){ + + let selectedCode = $(codeExampleControl).find('input[name="api-access-example-code"]:checked').val(); + + $(codeBlocks).each(function(_index, _codeBlock){ + + if( $(_codeBlock).hasClass(selectedCode) ){ + + $(_codeBlock).show(); + + }else{ + + $(_codeBlock).hide(); + + } + + }); + + }); + + } + + } + + // Activity tab link + let activityTab = $('#activity-lnk'); + + if( activityTab.length > 0 ){ + + let link = $('#activity').find('a').first().attr('href'); + + if( link && link.length > 0 ){ + + $(activityTab).attr('href', link); + $(activityTab).removeAttr('aria-controls'); + $(activityTab).attr('tabindex', 0); + + $(activityTab).off('click'); + $(activityTab).off('keyup'); + + function _goto_activity(){ + window.location = link; + } + + $(activityTab).on('click.Link', function(_event){ + _event.preventDefault(); + _goto_activity(); + }); + $(activityTab).on('keyup.Link', function(_event){ + let keyCode = _event.keyCode ? _event.keyCode : _event.which; + // space and enter keys required for a11y + if( keyCode == 32 || keyCode == 13 ){ + _event.preventDefault(); + _goto_activity(); + } + }); + + } + + } + + }); +}); diff --git a/ckanext/recombinant/assets/webassets.yml b/ckanext/recombinant/assets/webassets.yml new file mode 100644 index 0000000..4bc93b0 --- /dev/null +++ b/ckanext/recombinant/assets/webassets.yml @@ -0,0 +1,9 @@ +code_block_buttons: + contents: + - js/code_block_buttons.js + output: recombinant/%(version)s_code_block_buttons.js + +main_css: + contents: + - css/recombinant.css + output: recombinant/%(version)s_recombinant.css diff --git a/ckanext/recombinant/plugins.py b/ckanext/recombinant/plugins.py index 63650f1..2eabc39 100644 --- a/ckanext/recombinant/plugins.py +++ b/ckanext/recombinant/plugins.py @@ -29,7 +29,7 @@ class RecombinantPlugin( def update_config(self, config): # add our templates p.toolkit.add_template_directory(config, 'templates') - p.toolkit.add_public_directory(config, 'public') + p.toolkit.add_resource('assets', 'recombinant') # read our configuration early self._tables_urls = config.get('recombinant.definitions', "" diff --git a/ckanext/recombinant/public/js/code_block_buttons.js b/ckanext/recombinant/public/js/code_block_buttons.js deleted file mode 100644 index 7d962fd..0000000 --- a/ckanext/recombinant/public/js/code_block_buttons.js +++ /dev/null @@ -1,18 +0,0 @@ -function langBtnFn() { - var codeBlockClass = "code-block", - codeBtnSelector = ".btn-code-lang", - $codeBlock = $("." + codeBlockClass), - $codeBtn = $(codeBtnSelector), - lang = this.className.match(/lang\-[^\s]*/)[0]; - if (lang) { - $codeBlock - .removeClass() - .addClass(codeBlockClass + " " + lang); - $codeBtn.removeClass("active"); - $(this).addClass("active"); - } -}; - -$('#activity-lnk').click(function() { - document.location.href = $("#activity-stream-link").attr('href'); -}); diff --git a/ckanext/recombinant/templates/recombinant/resource_edit.html b/ckanext/recombinant/templates/recombinant/resource_edit.html index dfe2770..2da5d0b 100644 --- a/ckanext/recombinant/templates/recombinant/resource_edit.html +++ b/ckanext/recombinant/templates/recombinant/resource_edit.html @@ -81,8 +81,7 @@ {{ _("API Access") }} - {% snippet "recombinant/snippets/api_access.html", - pkg=dataset, username=c.userobj.name, resource=resource %} + {% snippet "recombinant/snippets/api_access.html", resource_id=resource.id, resource_name=resource.name, is_modal=false %}
@@ -142,18 +141,12 @@

{{_("Create and update records")}}

{% endblock action_panels %} {% endblock %} -{# syntax hilighting for API docs above #} {% block links %} -{{ super() }} - + {{ super() }} + {% asset 'recombinant/main_css' %} {% endblock %} -{%- block scripts %} +{%- block scripts -%} {{ super() }} - -{% endblock %} + {% asset 'recombinant/code_block_buttons' %} +{%- endblock -%} diff --git a/ckanext/recombinant/templates/recombinant/snippets/api_access.html b/ckanext/recombinant/templates/recombinant/snippets/api_access.html index 01c9088..206cad8 100644 --- a/ckanext/recombinant/templates/recombinant/snippets/api_access.html +++ b/ckanext/recombinant/templates/recombinant/snippets/api_access.html @@ -1,44 +1,58 @@ -{% set resource_id = resource.id %} -{% set profile_url = h.url_for('user.read', id=username) %} -

{{ _("API access examples") }}

-
- - - +{% set profile_url = h.url_for('user.read', id=g.userobj.name) %} +{% if not is_modal %} +

{{ _("API access examples") }}

+{% endif %} +
+ + +
-
-

{{ _("Retrieve Records") }}

-

{% trans %}Access this data through the CKAN Datastore API with resource_id="{{ resource_id }}"{% endtrans %} -

-

{% trans %}The CKAN API uses a JSON-RPC style, where you post a JSON object and receive another JSON object in response.{% endtrans %}

-

{% trans %}Retrieving records requires an API key. Your API key is shown on your profile page.{% endtrans %} -

- -

{% trans %}Do not include your API key in any code shared with other people. Use a configuration file or environment variable to let each user input their own key when they use your tool. Your API key is equivalent to your password and may be used to perform any action your user can on this site. All actions made with your API key will be logged as actions you performed.{% endtrans %} -

- -
{{ _("Example:") }}
-
+  
+

+ +

+
+
+

{% trans %}Access this data through the CKAN Datastore API with resource_id="{{ resource_id }}"{% endtrans %}

+

{% trans %}The CKAN API uses a JSON-RPC style, where you post a JSON object and receive another JSON object in response.{% endtrans %}

+

{% trans %}Retrieving records requires an API key. Your API key is shown on your profile page.{% endtrans %}

+

{% trans %}Do not include your API key in any code shared with other people. Use a configuration file or environment variable to let each user input their own key when they use your tool. Your API key is equivalent to your password and may be used to perform any action your user can on this site. All actions made with your API key will be logged as actions you performed.{% endtrans %}

+ {{ _("Example:") }} +
+
curl {{ g.site_url }}/api/action/datastore_search \
   -H"Authorization:$API_KEY" -d '
 {
   "resource_id": "{{ resource_id }}",
-  "sort": {{ h.recombinant_example(resource.name, 'sort') }},
+  "sort": {{ h.recombinant_example(resource_name, 'sort') }},
   "limit": 10,
   "filters": {
-{{ h.recombinant_example(resource.name, 'filters', indent=4) }}
+{{ h.recombinant_example(resource_name, 'filters', indent=4) }}
   }
 }'
 
-
 cURL
+
+
+
$json = @'
 {
   "resource_id": "{{ resource_id }}",
-  "sort": {{ h.recombinant_example(resource.name, 'sort') }},
+  "sort": {{ h.recombinant_example(resource_name, 'sort') }},
   "limit": 10,
   "filters": {
-{{ h.recombinant_example(resource.name, 'filters', indent=4) }}
+{{ h.recombinant_example(resource_name, 'filters', indent=4) }}
   }
 }
 '@
@@ -46,75 +60,107 @@ 
{{ _("Example:") }}
-Method Post -Body $json -Headers @{"Authorization"="$API_KEY"} $response.result.records
-
 PowerShell
+
+
+
from ckanapi import RemoteCKAN
 from pprint import pprint
 ckan = RemoteCKAN('{{ g.site_url }}', apikey=API_KEY)
 result = ckan.action.datastore_search(
     resource_id="{{ resource_id }}",
-    sort={{ h.recombinant_example(resource.name, 'sort') }},
+    sort={{ h.recombinant_example(resource_name, 'sort') }},
     limit=10,
     filters={
-{{ h.recombinant_example(resource.name, 'filters', indent=8) }}
+{{ h.recombinant_example(resource_name, 'filters', indent=8) }}
     }
 )
 pprint(result['records'])
+
 Python
+
+
+
+
-

{{ _("Create and Update Records") }}

-

{% trans %}Create and update records with the "datastore_upsert" endpoint.{% endtrans %}

- -
{{ _("Example:") }}
-
+    

+ +

+
+
+

{% trans %}Create and update records with the "datastore_upsert" endpoint.{% endtrans %}

+ {{ _("Example:") }} +
+
curl {{ g.site_url }}/api/action/datastore_upsert \
   -H"Authorization:$API_KEY" -d '
 {
   "resource_id": "{{ resource_id }}",
   "records": [{
-{{ h.recombinant_example(resource.name, 'record', indent=4) }}
+{{ h.recombinant_example(resource_name, 'record', indent=4) }}
   }]
 }'
-
 cURL
+
+
+
$json = @'
 {
   "resource_id": "{{ resource_id }}",
   "records": [{
-{{ h.recombinant_example(resource.name, 'record', indent=4) }}
+{{ h.recombinant_example(resource_name, 'record', indent=4) }}
   }]
 }
 '@
 $response = Invoke-RestMethod {{ g.site_url }}/api/action/datastore_upsert `
   -Method Post -Body $json -Headers @{"Authorization"="$API_KEY"}
 
-
 PowerShell
+
+
+
from ckanapi import RemoteCKAN
 ckan = RemoteCKAN('{{ g.site_url }}', apikey=API_KEY)
 result = ckan.action.datastore_upsert(
     resource_id="{{ resource_id }}",
     records=[{
-{{ h.recombinant_example(resource.name, 'record', indent=8) }}
+{{ h.recombinant_example(resource_name, 'record', indent=8) }}
     }]
 )
+
 Python
+
+
+
+
-

{{ _("Delete Records") }}

-

{% trans %}First verify that the record you would like to remove is present with the "datastore_search" endpoint{% endtrans %}

- -

{{ _("Example:") }}
-
+    

+ +

+
+
+

{% trans %}First verify that the record you would like to remove is present with the "datastore_search" endpoint{% endtrans %}

+ {{ _("Example:") }} +

+
curl {{ g.site_url }}/api/action/datastore_search \
   -H"Authorization:$API_KEY" -d '
 {
   "resource_id": "{{ resource_id }}",
   "filters": {
-{{ h.recombinant_example(resource.name, 'filter_one', indent=4) }}
+{{ h.recombinant_example(resource_name, 'filter_one', indent=4) }}
   }
 }'
 
-
 cURL
+
+
+
$json = @'
 {
   "resource_id": "{{ resource_id }}",
   "records": [{
-{{ h.recombinant_example(resource.name, 'filter_one', indent=4) }}
+{{ h.recombinant_example(resource_name, 'filter_one', indent=4) }}
   }]
 }
 '@
@@ -122,52 +168,67 @@ 
{{ _("Example:") }}
-Method Post -Body $json -Headers @{"Authorization"="$API_KEY"} $response.result.records
-
 PowerShell
+
+
+
from ckanapi import RemoteCKAN
 from pprint import pprint
 ckan = RemoteCKAN('{{ g.site_url }}', apikey=API_KEY)
 result = ckan.action.datastore_search(
     resource_id="{{ resource_id }}",
     filters={
-{{ h.recombinant_example(resource.name, 'filter_one', indent=8) }}
+{{ h.recombinant_example(resource_name, 'filter_one', indent=8) }}
     }
 )
 pprint(result['records'])
- -

{% trans %}Remove the record returned by passing the same parameters to the "datastore_records_delete" endpoint instead of "datastore_search".{% endtrans %}

- -
{{ _("Example:") }}
-
 Python
+
+

{% trans %}Remove the record returned by passing the same parameters to the "datastore_records_delete" endpoint instead of "datastore_search".{% endtrans %}

+ {{ _("Example:") }} +
+
curl {{ g.site_url }}/api/action/datastore_records_delete \
  -H"Authorization:$API_KEY" -d '
 {
   "resource_id": "{{ resource_id }}",
   "filters": {
-{{ h.recombinant_example(resource.name, 'filter_one', indent=4) }}
+{{ h.recombinant_example(resource_name, 'filter_one', indent=4) }}
   }
 }'
 
-
 cURL
+
+
+
$json = @'
 {
   "resource_id": "{{ resource_id }}",
   "filters": {
-{{ h.recombinant_example(resource.name, 'filter_one', indent=4) }}
+{{ h.recombinant_example(resource_name, 'filter_one', indent=4) }}
   }
 '@
 >$response = Invoke-RestMethod {{ g.site_url }}/api/action/datastore_records_delete `
   -Method Post -Body $json -Headers @{"Authorization"="$API_KEY"}
 
-
 PowerShell
+
+
+
from ckanapi import RemoteCKAN
 ckan = RemoteCKAN('{{ g.site_url }}', apikey=API_KEY)
 ckan.action.datastore_records_delete(
     resource_id="{{ resource_id }}",
     filters={
-{{ h.recombinant_example(resource.name, 'filter_one', indent=8) }}
+{{ h.recombinant_example(resource_name, 'filter_one', indent=8) }}
     }
 )
-
-

-{% trans %}If you have modified these API Access instructions for another programming language please send them to open-ouvert@tbs-sct.gc.ca and we may be able to post them here as well. {% endtrans %} -

+
 Python
+ +
+
+ + + + +

{% trans %}If you have modified these API Access instructions for another programming language please send them to open-ouvert@tbs-sct.gc.ca and we may be able to post them here as well.{% endtrans %}