{"id":36701993,"url":"https://github.com/noi-techpark/opendatahub-content-api","last_synced_at":"2026-01-12T11:39:04.535Z","repository":{"id":37850518,"uuid":"166447227","full_name":"noi-techpark/opendatahub-content-api","owner":"noi-techpark","description":".Net Core Port of Open Data Hub Tourism Api","archived":false,"fork":false,"pushed_at":"2025-12-19T18:05:22.000Z","size":98829,"stargazers_count":4,"open_issues_count":65,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-19T21:14:31.852Z","etag":null,"topics":["content","open-data","opendatahub"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/noi-techpark.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-01-18T17:27:32.000Z","updated_at":"2025-12-18T08:34:40.000Z","dependencies_parsed_at":"2025-11-27T14:02:01.444Z","dependency_job_id":null,"html_url":"https://github.com/noi-techpark/opendatahub-content-api","commit_stats":null,"previous_names":["noi-techpark/opendatahub-content-api","noi-techpark/odh-api-core"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/noi-techpark/opendatahub-content-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noi-techpark%2Fopendatahub-content-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noi-techpark%2Fopendatahub-content-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noi-techpark%2Fopendatahub-content-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noi-techpark%2Fopendatahub-content-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/noi-techpark","download_url":"https://codeload.github.com/noi-techpark/opendatahub-content-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noi-techpark%2Fopendatahub-content-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T10:58:46.209Z","status":"ssl_error","status_checked_at":"2026-01-12T10:58:42.742Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["content","open-data","opendatahub"],"created_at":"2026-01-12T11:39:04.453Z","updated_at":"2026-01-12T11:39:04.528Z","avatar_url":"https://github.com/noi-techpark.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\nSPDX-FileCopyrightText: NOI Techpark \u003cdigital@noi.bz.it\u003e\n\nSPDX-License-Identifier: CC0-1.0\n--\u003e\n\n# opendatahub-content-api\n\nPort of Open Data Hub Tourism Api to .Net Core.\n\n[![REUSE Compliance](https://github.com/noi-techpark/opendatahub-content-api/actions/workflows/reuse.yml/badge.svg)](https://github.com/noi-techpark/opendatahub-docs/wiki/REUSE#badges)\n[![CI/CD API](https://github.com/noi-techpark/opendatahub-content-api/actions/workflows/main_api.yml/badge.svg)](https://github.com/noi-techpark/opendatahub-content-api/actions/workflows/main_api.yml)\n[![CI/CD Importer](https://github.com/noi-techpark/opendatahub-content-api/actions/workflows/main_importer.yml/badge.svg)](https://github.com/noi-techpark/opendatahub-content-api/actions/workflows/main_importer.yml)\n\n## Project Goals/Requirements:\n\n* .Net Core 5\n* PostgreSQL Database\n* Docker Support\n* Swagger Support\n* Identity Server Integration (Keycloak)\n* Full Async Api\n* improved Api Error Handling\n* Browseable Api\n* Swagger / Openapi Support\n* Advanced api operations 1/2 (fields chooser, language selector, search terms)\n* Advanced api operation 2/2 (raw sorting, raw filtering)\n* Compatibility tourism api\n\n## Project Structure\n\nTest Server on https://tourism.api.opendatahub.testingmachine.eu  \nProduction Server on https://tourism.api.opendatahub.com\n\n### DataModel\n\nDefinition of all Open Data Hub Tourism Models. Available as Nuget package (https://www.nuget.org/packages/opendatahub-datamodel-tourism)\n\n### Open Data Hub Api Core (OdhApiCore)\n\nApi to retrieve Open Data Hub Tourism Data\n\n### Open Data Hub Importer (OdhApiImporter)\n\nWorkerservice which is importing the Data with help of the Data Collectors\n\n### Helper\n\nClass Library with Extension Methods and other Open Data Hub Tourism Helper Methods\n\n### CDB, DSS, EBMS, LCS, MSS, NINJA, RAVEN, SIAG, STA, SuedtirolWein, A22, FERATEL, LOOPTEC, PANOMAX, PANOCLOUD\n\nData Collectors used by Api and Importer, usually containing classes that retrieve Data, and classes that parse the data to Open Data Hub Objects (defined in DataModel)\n\n### GeoConverter\n\nHelper Library which allows converting  \nkml to GeoJson  \ngpx to GeoJson\n\n### JsonLDTransformer\n\nHelper Library which converts Open Data Hub Content Api Objects to schema.org Models in ld+json format.\n\n### Open Data Hub Notifier (OdhNotifier)\n\nComponent which notifies pre configured Consumers about Data Changes\n\n### PushServer\n\nComponent which generateds Push Messages (Firebase Cloud Messaging)\n\n### RawQueryParser\n\nHelper Library where the rawfilter/rawsort functionality is implemented.\n\n## Database\n\nPostgres 15. The data is stored as Json Datatype in a single Column.\n\n### Extensions\n\nExtensions active on DB\n\n* extension earthdistance;\n* extension cube;\n* extension pg_trgm;\n* extension postgis\n\n### Custom Functions\n\nCustom Functions on DB\n\n* json_array_to_pg_array\n* extract_keys_from_jsonb_object_array\n* text2ts\n* json_array_to_pg_array\n* extract_keys_from_jsonb_object_array\n* extract_tags\n* extract_tagkeys\n* is_valid_jsonb\n* json_2_tsrange_array\n* convert_tsrange_array_to_tsmultirange\n* json_2_ts_array\n* get_abs_eventdate_single\n\nThese custom functions are used for the generated Columns\n\n### Generated Columns\n\nTo speed up certain filters this project uses generated Columns where certain fields of the json data\nis modelled as columns where indices can be set.\n\n### Indices\n\nDifferent Indices used\n- btree indices (Single column indices)\n- gin indices (Index for the Json Column)\n- gist indices (Indices to speed up distance search)\n- trigram indices (Indices to speed up Title search)\n\n\n\n## Getting started:\n\nClone the repository  \nCopy `.env.example` to `.env`  \nSet the needed environment variables\n\n### Environment Variables\n\n* PG_CONNECTION (Connection to Postgres Database)\n* MSS_USER; (Optional User to retrieve availability request from HGV Mss)\n* MSS_PSWD; (Optional Pswd to retrieve availability request from HGV Mss)\n* LCS_USER; (Optional User to retrieve availability request from Lts)\n* LCS_PSWD; (Optional Pswd to retrieve availability request from Lts)\n* LCS_MSGPSWD; (Optional Messagepswd to retrieve availability requests from LTS)\n* SIAG_USER; (Optional User to retrieve data from Siag)\n* SIAG_PSWD; (Optional Pswd to retrieve data from Siag)\n* XMLDIR; (Directory where xml config file is stored)\n* JSONPATH; (Directory where json files are stored)\n* S3_BUCKET_ACCESSPOINT; (S3 Bucket for Image Upload accesspoint)\n* S3_IMAGEUPLOADER_ACCESSKEY; (S3 Bucket for Image Upload accesskey)\n* S3_IMAGEUPLOADER_SECRETKEY; (S3 Bucket for Image Upload secretkey)\n* OAUTH_AUTORITY; (Oauth Server Authority URL)\n* ELK_URL; (Serilog Elasticsearch Sink Elastic URL)\n* ELK_TOKEN; (Serilog Elasticsearch Access Token)\n* EBMS_USER; (Optional User to access EBMS interface)\n* EBMS_PASS; (Optional Pswd to access EBMS interface)\n* DSS_USER; (Optional User to access DSS interface)\n* DSS_PSWD; (Optional Pswd to access DSS interface)\n* DSS_SERVICEURL; (Optional DSS interface serviceurl)\n* RAVEN_USER; (Optional User to access Raven interface)\n* RAVEN_PSWD; (Optional Pswd to access Raven interface)\n* RAVEN_SERVICEURL; (Optional Raven interface serviceurl)\n\n### using Docker\n\ngo into \\OdhApiCore\\ folder \\\n`docker-compose up` starts the Open Data Hub Content Api application on http://localhost:8001/\n\ngo into \\OdhApiImporter\\ folder \\\n`docker-compose up` starts the  Open Data Hub Content Api application on http://localhost:8002/\n\n### using .Net Core CLI\n\nInstall .Net Core SDK 5\\\ngo into \\OdhApiCore\\ folder \\\n`dotnet run`\nstarts the application on \nhttps://localhost:5001;\nhttp://localhost:5000\n\n### Postgres\n\nActivate extensions\n\n```\nCREATE EXTENSION cube;\n```\n```\nCREATE EXTENSION earthdistance;\n```\n```\nCREATE EXTENSION pg_trgm;\n```\n```\nCREATE EXTENSION postgis;\n```\n\nCreate generated columns on Postgres\n\n* bool\n\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_bool bool GENERATED ALWAYS AS ((data#\u003e'{Active}')::bool)stored;\n```\n\n*string\n\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_string text GENERATED ALWAYS AS ((data#\u003e\u003e'{Source}'))stored;\n```\n\n*double\n\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_double DOUBLE precision GENERATED ALWAYS AS ((data#\u003e'{Latitude}')::DOUBLE precision) stored;\n```\n\n* array (simple)\n\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_array text[] GENERATED ALWAYS AS (json_array_to_pg_array(data#\u003e'{HasLanguage}')) stored;\n```\n\n* array (object)\n\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_array text[] GENERATED ALWAYS AS (extract_keys_from_jsonb_object_array(data#\u003e'{Features}','Id')) stored;\n```\n\n* date\n\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_date timestamp GENERATED ALWAYS AS (text2ts(data#\u003e\u003e'{LastChange}')::timestamp) stored;\n```\n\n* tsarray\n```sql\nALTER TABLE events ADD IF NOT EXISTS gen_tsarray timestamp[] GENERATED ALWAYS AS (json_2_ts_array(data#\u003e'{EventDate}')) stored;\n```\n\n* tsrangearray\n```sql\nALTER TABLE events ADD IF NOT EXISTS gen_tsrangearray tsrange[] GENERATED ALWAYS AS (json_2_tsrange_array(data#\u003e'{EventDate}')) stored;\n```\n\n* tsmultirange\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_tsmultirange tsmultirange GENERATED ALWAYS AS (convert_tsrange_array_to_tsmultirange(json_2_tsrange_array(data#\u003e'{EventDate}'))) stored;\n```\n\n* jsonb\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_jsonb jsonb GENERATED ALWAYS AS ((data#\u003e'{SomeJsonB}')::jsonb) stored;\n```\n\n* geometry (postgis)\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_position public.geometry GENERATED ALWAYS AS (st_setsrid(st_makepoint((data #\u003e '{GpsPoints,position,Longitude}'::text[])::double precision, (data #\u003e '{GpsPoints,position,Latitude}'::text[])::double precision), 4326)) STORED NULL;\n```\n\n* access_based\n```sql\nALTER TABLE tablename ADD IF NOT EXISTS gen_access_role text[] GENERATED ALWAYS AS (calculate_access_array(data#\u003e\u003e'{_Meta,Source}',(data#\u003e'{LicenseInfo,ClosedData}')::bool,(data#\u003e'{_Meta,Reduced}')::bool)) stored;\n```\n \n\nCustom functions for Postgres Generated Columns creation\n\n* text2ts\n\n```sql\nCREATE OR REPLACE FUNCTION text2ts(text)\n RETURNS timestamp without time zone\n LANGUAGE sql\n IMMUTABLE\nAS $function$SELECT CASE WHEN $1 ~'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(?:Z|\\+\\d{2}:\\d{2})?$' THEN CAST($1 AS timestamp without time zone) END; $function$;\n```\n* json_array_to_pg_array\n\n```sql\nCREATE OR REPLACE FUNCTION json_array_to_pg_array(jsonarray jsonb)\n RETURNS text[]\n LANGUAGE plpgsql\n IMMUTABLE STRICT\nAS $function$ begin if jsonarray \u003c\u003e 'null' then return (select array(select jsonb_array_elements_text(jsonarray))); else return null; end if; end; $function$;\n```\n\n* extract_keys_from_jsonb_object_array\n\n```sql\nCREATE OR REPLACE FUNCTION extract_keys_from_jsonb_object_array(jsonarray jsonb, key text DEFAULT 'Id'::text)\n RETURNS text[]\n LANGUAGE plpgsql\n IMMUTABLE STRICT\nAS $function$ begin if jsonarray \u003c\u003e 'null' then return (select array(select data2::jsonb-\u003e\u003e key from (select jsonb_array_elements_text(jsonarray) as data2) as subsel)); else return null; end if; end; $function$;\n```\n\n* extract_tags\n\n```sql\nCREATE OR REPLACE FUNCTION public.extract_tags(jsonarray jsonb)\n RETURNS text[]\n LANGUAGE plpgsql\n IMMUTABLE strict\nAS $function$ begin\n\treturn\n\t\t(select array(select concat(x.tags-\u003e\u003e'Source', '.', x.tags-\u003e\u003e'Id') from\n\t\t(select jsonb_path_query(jsonarray, '$.*[*]') tags) x) x);\nend; $function$\n```\n\n* extract_tagkeys\n\n```sql\nCREATE OR REPLACE FUNCTION public.extract_tagkeys(jsonarray jsonb)\n RETURNS text[]\n LANGUAGE plpgsql\n IMMUTABLE strict\nAS $function$ begin\n\treturn (array(select distinct unnest(json_array_to_pg_array(jsonb_path_query_array(jsonarray, '$.*[*].Id')))));\nend; $function$\n```\n\n* is_valid_jsonb\n\n```sql\nCREATE OR REPLACE FUNCTION is_valid_jsonb(p_json text) \nRETURNS JSONB\nAS $$\nbegin\n  return p_json::jsonb;\nexception \n  when others then\n     return null;  \nend; $$ \nLANGUAGE plpgsql IMMUTABLE;\n```\n\n* json_2_ts_array\n\n```sql\nCREATE OR REPLACE FUNCTION public.json_2_ts_array(jsonarray jsonb)\n RETURNS timestamp[]\n LANGUAGE plpgsql\n IMMUTABLE STRICT\nAS $function$ begin if jsonarray \u003c\u003e 'null' then return (\n  select \n    array(\n      select \n        (event -\u003e\u003e 'From')::timestamp + (event -\u003e\u003e 'Begin')::time        \n      from \n        jsonb_array_elements(jsonarray) as event \n      where \n        (event -\u003e\u003e 'From')::timestamp + (event -\u003e\u003e 'Begin')::time \u003c (event -\u003e\u003e 'To')::timestamp + (event -\u003e\u003e 'End')::time\n    )\n);\nelse return null;\nend if;\nend;\n$function$\n;\n```\n\n* json_2_tsrange_array\n\nUsed on Events, creates a TSRange Array from EventDate Json\n\n```sql\nCREATE OR REPLACE FUNCTION public.json_2_tsrange_array(jsonarray jsonb)\n RETURNS tsrange[]\n LANGUAGE plpgsql\n IMMUTABLE STRICT\nAS $function$ begin if jsonarray \u003c\u003e 'null' then return (\n  select \n    array(\n      select \n        tsrange(\n          ( (event -\u003e\u003e 'From')::timestamp + (event -\u003e\u003e 'Begin')::time), \n          ( (event -\u003e\u003e 'To')::timestamp + (event -\u003e\u003e 'End')::time)\n        ) \n      from \n        jsonb_array_elements(jsonarray) as event \n      where \n        (event -\u003e\u003e 'From')::timestamp + (event -\u003e\u003e 'Begin')::time \u003c (event -\u003e\u003e 'To')::timestamp + (event -\u003e\u003e 'End')::time\n    )\n);\nelse return null;\nend if;\nend;\n$function$\n```\n\n* convert_tsrange_array_to_tsmultirange\n\n```sql\nCREATE OR REPLACE FUNCTION convert_tsrange_array_to_tsmultirange(tsrange_array tsrange[])\nRETURNS tsmultirange\nLANGUAGE plpgsql\n IMMUTABLE STRICT\nAS $$\nDECLARE\n    result tsmultirange := tsmultirange();\n    tsr tsrange;\nBEGIN\n\tIF tsrange_array IS NOT NULL THEN\n    -- Durchlaufen des tsrange-Arrays\n    FOREACH tsr IN ARRAY tsrange_array\n    LOOP\n        -- Hinzufügen des tsrange-Elements zum tsmultirange\n        result := result + tsmultirange(tsrange(tsr));\n    END LOOP;\n\tEND IF;\n\n    RETURN result;\nEND;\n$$;\n```\n\n* calculate_access_array\n\n```sql\nCREATE OR REPLACE FUNCTION public.calculate_access_array(source text, closeddata bool, reduced bool)\nRETURNS text[]\nLANGUAGE plpgsql\nIMMUTABLE\nAS $function$\nbegin\n-- If data is from source lts and not reduced IDM only access --\nif source = 'lts' and not reduced then return (array['IDM']);\nend if;\n-- If data is from source hgv only access IDM --\nif source = 'hgv' then return (array['IDM']);\nend if;\n-- If data is from source a22 only access A22 --\nif source = 'a22' then return (array['A22']);\nend if;\n-- If data is from source LTS and reduced give access to all others --\nif source = 'lts' and reduced and not closeddata then return (array['A22','ANONYMOUS','STA']);\nend if;\n-- If data is not from source lts and a22 and not closed data give all access --\nif source \u003c\u003e 'lts' and source \u003c\u003e 'a22' and not closeddata then return (array['A22','ANONYMOUS','IDM','STA']);\nend if;\nreturn (array['A22','ANONYMOUS','IDM','STA']);\nend;\n$function$\n\n//For the rawdata table\nCREATE OR REPLACE FUNCTION public.calculate_access_array_rawdata(source text, license text)\n RETURNS text[]\n LANGUAGE plpgsql\n IMMUTABLE\nAS $function$\nbegin\n-- If data is from source lts and not reduced IDM only access --\nif source = 'lts' then return (array['IDM']);\nend if;\n-- If data is from source hgv only access IDM --\nif source = 'hgv' then return (array['IDM']);\nend if;\n-- If data is from source a22 only access A22 --\nif source = 'a22' then return (array['A22']);\nend if;\n-- If data is not from source lts and a22 and not closed data give all access --\nif source \u003c\u003e 'lts' and source \u003c\u003e 'a22' then return (array['A22','ANONYMOUS','IDM','STA']);\nend if;\nreturn (array['A22','ANONYMOUS','IDM','STA']);\nend;\n$function$\n;\n```\n\n* get_nearest_tsrange_distance\n\nUsed on Events calculates the difference between a given date and it's next Date Interval\n\n```sql\n--calculates the distance from given date\nCREATE OR REPLACE FUNCTION public.get_nearest_tsrange_distance(tsrange_array tsrange[], ts_tocalculate timestamp without time zone, sortorder text, prioritizesingledayevents bool)\n RETURNS bigint\n LANGUAGE plpgsql\n IMMUTABLE STRICT\nAS $function$\nDECLARE    \n\tresult bigint;\n\tintarr bigint[];\n\tmytsrange tsrange;\n    tsr timestamp;\n    singledayadd int;\n\nBEGIN\n\tIF tsrange_array IS NOT NULL THEN\n    -- Iterate trough Array\n    FOREACH mytsrange IN array tsrange_array\n    loop\n\t    singledayadd = 0;\n\t   \n\t   if(prioritizesingledayevents = true) then\n\t    \n\t    -- if prioritiyesingledayevents is used, increase all distances for multidayevents with 1\n\t\t     if(lower(mytsrange)::date = upper(mytsrange)::date) then\n\t         \tsingledayadd = 0;\n\t         else\n\t         \tsingledayadd = 1;\n\t         end if;\n\t        \n\t   end if;\n\t    \n\t    -- get tsrange which is matching (ongoing event) and add 0\n\t    if mytsrange @\u003e ts_tocalculate then\n           intarr := array_append(intarr, singledayadd);\n        else\n       -- check if period has already ended\n           if upper(mytsrange)::timestamp \u003e ts_tocalculate then\n               --if period has not ended calculate distance\n               intarr := array_append(intarr, extract(epoch from (lower(mytsrange)::timestamp - ts_tocalculate))::bigint + singledayadd);\n\t    \t\n           end if;\n        \n       end if;\n       \n    END LOOP;\n\n      --get distance (default minimum distance is returned, desc gets the highest distance)\n\t  if sortorder = 'desc' then\n\t  \tresult = (select unnest(intarr) as x order by x desc limit 1);\n\t  else\n\t   result = (select unnest(intarr) as x order by x asc limit 1);\n\t  end if;\n   \t  \n\tEND IF;\t\t\n\n    RETURN result;\nEND;\n$function$\n;\n```\n\n* get_nearest_tsrange\n\nUsed on Events, gets the next Date Interval to a passed date as TSRange\n\n```sql\n-- GETS the next tsrange to a given date\nCREATE OR REPLACE FUNCTION public.get_nearest_tsrange(tsrange_array tsrange[], ts_tocalculate timestamp without time zone)\n RETURNS tsrange\n LANGUAGE plpgsql\n IMMUTABLE STRICT\nAS $function$\nDECLARE    \n\tresult tsrange;\n\tdistance bigint;\n    distancetemp bigint;\n\tmytsrange tsrange;\n    tsr timestamp;    \nBEGIN\n\tIF tsrange_array IS NOT NULL then\n\t\n\tdistance = 9999999999;\n\t-- Iterate trough Array\n    FOREACH mytsrange IN array tsrange_array\n    loop\n\t    -- get tsrange which is matching (ongoing event)\n\t    if mytsrange @\u003e ts_tocalculate then\n            result = mytsrange;\n            distance = 0;\n        else\n       -- check if period has already ended\n           if upper(mytsrange)::timestamp \u003e ts_tocalculate then\n           \n               --if period has not ended calculate distance\n               distancetemp = extract(epoch from (lower(mytsrange)::timestamp - ts_tocalculate))::bigint;\n\t    \t\n              if(distance \u003e distancetemp) then\n              \tdistance = distancetemp;\n              \tresult = mytsrange;\n              end if;\n              \n           end if;\n        \n       end if;\n       \n    END LOOP;\n \n\tEND IF;\t\t\n\n    RETURN result;\nEND;\n$function$\n;\n```\n\n### REUSE\n\nThis project is [REUSE](https://reuse.software) compliant, more information about the usage of REUSE in NOI Techpark repositories can be found [here](https://github.com/noi-techpark/opendatahub-docs/wiki/Guidelines-for-developers-and-licenses#guidelines-for-contributors-and-new-developers).\n\nSince the CI for this project checks for REUSE compliance you might find it useful to use a pre-commit hook checking for REUSE compliance locally. The [pre-commit-config](.pre-commit-config.yaml) file in the repository root is already configured to check for REUSE compliance with help of the [pre-commit](https://pre-commit.com) tool.\n\nInstall the tool by running:\n```bash\npip install pre-commit\n```\nThen install the pre-commit hook via the config file by running:\n```bash\npre-commit install\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoi-techpark%2Fopendatahub-content-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoi-techpark%2Fopendatahub-content-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoi-techpark%2Fopendatahub-content-api/lists"}