{"version":3,"file":"js/app.7f305149.js","mappings":"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","sources":["webpack://linnunrata/./frontend-src/filters.ts","webpack://linnunrata/./frontend-src/App.vue?a77b","webpack://linnunrata/frontend-src/App.vue","webpack://linnunrata/./frontend-src/App.vue?5dce","webpack://linnunrata/./frontend-src/App.vue","webpack://linnunrata/./frontend-src/views/course.vue?aad1","webpack://linnunrata/./frontend-src/api/runtime.ts","webpack://linnunrata/./frontend-src/api/models/CourseSortOrder.ts","webpack://linnunrata/./frontend-src/api/models/Geopoint.ts","webpack://linnunrata/./frontend-src/api/models/HellewiAgeLimits.ts","webpack://linnunrata/./frontend-src/api/models/HellewiLocation.ts","webpack://linnunrata/./frontend-src/api/models/HellewiTenantType.ts","webpack://linnunrata/./frontend-src/api/models/HellewiLessonParticipantCount.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseLesson.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalogItemType.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalogItem.ts","webpack://linnunrata/./frontend-src/api/models/Weekday.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseDay.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseMinimal.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseMinimalParent.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseNotificationLabel.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseNotification.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePeriod.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePriceInstallmentInstallmentsInner.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePriceInstallment.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseProduct.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePrice.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseStatus.ts","webpack://linnunrata/./frontend-src/api/models/HellewiLanguage.ts","webpack://linnunrata/./frontend-src/api/models/HellewiTag.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePartial.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalog.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalogSettingsEnabledCatalogItemTypes.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalogSettings.ts","webpack://linnunrata/./frontend-src/api/models/HellewiFile.ts","webpack://linnunrata/./frontend-src/api/models/HellewiImage.ts","webpack://linnunrata/./frontend-src/api/models/HellewiParticipantCount.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourse.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseCount.ts","webpack://linnunrata/./frontend-src/api/models/HellewiTenant.ts","webpack://linnunrata/./frontend-src/api/apis/BrandApi.ts","webpack://linnunrata/./frontend-src/utils/api-utils.ts","webpack://linnunrata/./frontend-src/api/apis/CatalogApi.ts","webpack://linnunrata/./frontend-src/api/apis/CourseApi.ts","webpack://linnunrata/./frontend-src/api/apis/TenantApi.ts","webpack://linnunrata/./frontend-src/utils/misc-utils.ts","webpack://linnunrata/./frontend-src/hooks/useCourseApi.ts","webpack://linnunrata/./frontend-src/components/header/header.vue?3879","webpack://linnunrata/./frontend-src/components/header/language-selection.vue?f93d","webpack://linnunrata/frontend-src/components/header/language-selection.vue","webpack://linnunrata/./frontend-src/components/header/language-selection.vue?018d","webpack://linnunrata/./frontend-src/components/header/language-selection.vue","webpack://linnunrata/./frontend-src/components/header/logo.vue?1825","webpack://linnunrata/frontend-src/components/header/logo.vue","webpack://linnunrata/./frontend-src/components/header/logo.vue?a4d0","webpack://linnunrata/./frontend-src/components/header/logo.vue","webpack://linnunrata/frontend-src/components/header/header.vue","webpack://linnunrata/./frontend-src/components/header/header.vue?b8cf","webpack://linnunrata/./frontend-src/components/header/header.vue","webpack://linnunrata/./frontend-src/components/header/header-mobile.vue?8208","webpack://linnunrata/frontend-src/components/header/header-mobile.vue","webpack://linnunrata/./frontend-src/components/header/header-mobile.vue?e49a","webpack://linnunrata/./frontend-src/components/header/header-mobile.vue","webpack://linnunrata/./frontend-src/components/footer.vue?e07a","webpack://linnunrata/frontend-src/components/footer.vue","webpack://linnunrata/./frontend-src/components/footer.vue?61c6","webpack://linnunrata/./frontend-src/components/footer.vue","webpack://linnunrata/./frontend-src/components/course-list/course-map.vue?275e","webpack://linnunrata/frontend-src/components/course-list/course-map.vue","webpack://linnunrata/./frontend-src/components/course-list/course-map.vue?1cfb","webpack://linnunrata/./frontend-src/components/course-list/course-map.vue","webpack://linnunrata/./frontend-src/components/course/registration-box.vue?9bce","webpack://linnunrata/./frontend-src/utils/availability-utils.ts","webpack://linnunrata/./frontend-src/utils/course-utils.ts","webpack://linnunrata/./frontend-src/utils/date-utils.ts","webpack://linnunrata/frontend-src/components/course/registration-box.vue","webpack://linnunrata/./frontend-src/components/course/registration-box.vue?d5e0","webpack://linnunrata/./frontend-src/components/course/registration-box.vue","webpack://linnunrata/./frontend-src/components/course/lessons-collapse.vue?9581","webpack://linnunrata/frontend-src/components/course/lessons-collapse.vue","webpack://linnunrata/./frontend-src/components/course/lessons-collapse.vue?d5af","webpack://linnunrata/./frontend-src/components/course/lessons-collapse.vue","webpack://linnunrata/frontend-src/views/course.vue","webpack://linnunrata/./frontend-src/views/course.vue?8169","webpack://linnunrata/./frontend-src/views/course.vue","webpack://linnunrata/./frontend-src/views/index.vue?76ac","webpack://linnunrata/./frontend-src/hooks/useCatalogApi.ts","webpack://linnunrata/./frontend-src/components/lander-search.vue?229d","webpack://linnunrata/./frontend-src/utils/location-utils.ts","webpack://linnunrata/frontend-src/components/lander-search.vue","webpack://linnunrata/./frontend-src/components/lander-search.vue?31d7","webpack://linnunrata/./frontend-src/components/lander-search.vue","webpack://linnunrata/./frontend-src/components/lander-categories.vue?5f9e","webpack://linnunrata/frontend-src/components/lander-categories.vue","webpack://linnunrata/./frontend-src/components/lander-categories.vue?9a10","webpack://linnunrata/./frontend-src/components/lander-categories.vue","webpack://linnunrata/frontend-src/views/index.vue","webpack://linnunrata/./frontend-src/views/index.vue?1da2","webpack://linnunrata/./frontend-src/views/index.vue","webpack://linnunrata/./frontend-src/views/language.vue?5e19","webpack://linnunrata/./frontend-src/hooks/useTenantApi.ts","webpack://linnunrata/frontend-src/views/language.vue","webpack://linnunrata/./frontend-src/views/language.vue?9ebe","webpack://linnunrata/./frontend-src/views/language.vue","webpack://linnunrata/./frontend-src/views/not-found.vue?b593","webpack://linnunrata/frontend-src/views/not-found.vue","webpack://linnunrata/./frontend-src/views/not-found.vue?f842","webpack://linnunrata/./frontend-src/views/not-found.vue","webpack://linnunrata/./frontend-src/views/search.vue?a431","webpack://linnunrata/./frontend-src/utils/query-utils.ts","webpack://linnunrata/./frontend-src/hooks/useSearch.ts","webpack://linnunrata/./frontend-src/components/course-list/course-list.vue?a396","webpack://linnunrata/./frontend-src/components/course-list/course-card.vue?b0ff","webpack://linnunrata/./frontend-src/hooks/useRouter.ts","webpack://linnunrata/./frontend-src/components/course-list/education-sectors.ts","webpack://linnunrata/frontend-src/components/course-list/course-card.vue","webpack://linnunrata/./frontend-src/components/course-list/course-card.vue?88b0","webpack://linnunrata/./frontend-src/components/course-list/course-card.vue","webpack://linnunrata/frontend-src/components/course-list/course-list.vue","webpack://linnunrata/./frontend-src/components/course-list/course-list.vue?4b31","webpack://linnunrata/./frontend-src/components/course-list/course-list.vue","webpack://linnunrata/./frontend-src/components/search/search-filters.vue?c5e2","webpack://linnunrata/./frontend-src/components/search/search-filter-dropdown.vue?74ec","webpack://linnunrata/frontend-src/components/search/search-filter-dropdown.vue","webpack://linnunrata/./frontend-src/components/search/search-filter-dropdown.vue?a80b","webpack://linnunrata/./frontend-src/components/search/search-filter-dropdown.vue","webpack://linnunrata/./frontend-src/components/search/search-filter-checkbox.vue?9958","webpack://linnunrata/frontend-src/components/search/search-filter-checkbox.vue","webpack://linnunrata/./frontend-src/components/search/search-filter-checkbox.vue?be08","webpack://linnunrata/./frontend-src/components/search/search-filter-checkbox.vue","webpack://linnunrata/frontend-src/components/search/search-filters.vue","webpack://linnunrata/./frontend-src/components/search/search-filters.vue?b22a","webpack://linnunrata/./frontend-src/components/search/search-filters.vue","webpack://linnunrata/./frontend-src/components/search/search-header/search-header-desktop.vue?5889","webpack://linnunrata/frontend-src/components/search/search-header/search-header-desktop.vue","webpack://linnunrata/./frontend-src/components/search/search-header/search-header-desktop.vue?de6d","webpack://linnunrata/./frontend-src/components/search/search-header/search-header-desktop.vue","webpack://linnunrata/./frontend-src/components/search/search-header/search-header-mobile.vue?e90a","webpack://linnunrata/frontend-src/components/search/search-header/search-header-mobile.vue","webpack://linnunrata/./frontend-src/components/search/search-header/search-header-mobile.vue?de68","webpack://linnunrata/./frontend-src/components/search/search-header/search-header-mobile.vue","webpack://linnunrata/./frontend-src/components/search/search-map.vue?b10b","webpack://linnunrata/frontend-src/components/search/search-map.vue","webpack://linnunrata/./frontend-src/components/search/search-map.vue?e162","webpack://linnunrata/./frontend-src/components/search/search-map.vue","webpack://linnunrata/./frontend-src/components/search/search-pagination.vue?39d5","webpack://linnunrata/frontend-src/components/search/search-pagination.vue","webpack://linnunrata/./frontend-src/components/search/search-pagination.vue?da3d","webpack://linnunrata/./frontend-src/components/search/search-pagination.vue","webpack://linnunrata/./frontend-src/components/service-providers/tenant-dropdown.vue?2ee0","webpack://linnunrata/frontend-src/components/service-providers/tenant-dropdown.vue","webpack://linnunrata/./frontend-src/components/service-providers/tenant-dropdown.vue?5a96","webpack://linnunrata/./frontend-src/components/service-providers/tenant-dropdown.vue","webpack://linnunrata/frontend-src/views/search.vue","webpack://linnunrata/./frontend-src/views/search.vue?230f","webpack://linnunrata/./frontend-src/views/search.vue","webpack://linnunrata/./frontend-src/views/service-providers.vue?422f","webpack://linnunrata/frontend-src/views/service-providers.vue","webpack://linnunrata/./frontend-src/views/service-providers.vue?4bb2","webpack://linnunrata/./frontend-src/views/service-providers.vue","webpack://linnunrata/./frontend-src/router.ts","webpack://linnunrata/./frontend-src/i18n.ts","webpack://linnunrata/./frontend-src/main.ts","webpack://linnunrata/webpack/bootstrap","webpack://linnunrata/webpack/runtime/chunk loaded","webpack://linnunrata/webpack/runtime/compat get default export","webpack://linnunrata/webpack/runtime/define property getters","webpack://linnunrata/webpack/runtime/global","webpack://linnunrata/webpack/runtime/hasOwnProperty shorthand","webpack://linnunrata/webpack/runtime/make namespace object","webpack://linnunrata/webpack/runtime/node module decorator","webpack://linnunrata/webpack/runtime/publicPath","webpack://linnunrata/webpack/runtime/jsonp chunk loading","webpack://linnunrata/webpack/startup"],"sourcesContent":["import {\n format,\n isSameDay,\n isSameMonth,\n isSameYear,\n isValid,\n setISODay,\n startOfDay,\n subMinutes\n} from 'date-fns';\n\n// use custom formatters for dates and times\n\nexport const DATE_FORMAT_FI = 'd.M.yyyy';\nexport const DATETIME_FORMAT_FI = 'd.M.yyyy H:mm';\nexport const TIME_FORMAT_FI = 'H:mm';\nexport const TIME_SECONDS_FORMAT_FI = 'H:mm:ss';\n\n/**\n * Formats a date in Finnish time format H:mm, e.g.\n * 12:04\n *\n * @param date date object, possibly null\n * @return time as string\n */\nexport const formatTime = (date: Date | null | undefined) =>\n date && isValid(date) ? format(date, TIME_FORMAT_FI) : '';\n\n/**\n * Formats a date in Finnish date format d.M.yyyy, e.g.\n * 1.5.2020\n *\n * @param date date object, possibly null\n * @return date as string\n */\nexport const formatDate = (date: Date | null | undefined) =>\n date && isValid(date) ? format(date, DATE_FORMAT_FI) : '';\n\n/**\n * Formats a date in Finnish date-time format d.M.yyyy H:mm, e.g.\n * 1.5.2020 12:04\n *\n * @param date date object, possibly null\n * @return time as string\n */\nexport const formatDateTime = (date: Date | null | undefined) =>\n date && isValid(date) ? format(date, DATETIME_FORMAT_FI) : '';\n\n/**\n * Formats a time range in Finnish time format H:mm-H:mm, e.g.\n * 12:00-12:05\n *\n * @param begins date object, possibly null\n * @param ends date object, possibly null\n * @return time range as string\n */\nexport const formatTimeRange = (\n begins: Date | null | undefined,\n ends: Date | null | undefined\n): string => {\n if (begins && ends && isValid(begins) && isValid(ends)) {\n return `${formatTime(begins)}\\u2013${formatTime(ends)}`;\n } else if (begins && isValid(begins)) {\n return formatTime(begins);\n } else if (ends && isValid(ends)) {\n return formatTime(ends);\n } else {\n return '';\n }\n};\n\n/**\n * Formats a date range in Finnish date format d.M.yyyy-d.M.yyyy, e.g.\n * 1.1.2020-1.5.2020\n *\n * If the dates are the same, return that 1.1.2020\n * If the dates have the same month and year, return 1.-2.1.2020\n * If the dates have the same year, return 1.1.-1.2.2020\n *\n * @param begins date object, possibly null\n * @param ends date object, possibly null\n * @return time range as string\n */\nexport const formatDateRange = (\n begins: Date | undefined | null,\n ends: Date | undefined | null\n): string => {\n if (\n begins &&\n ends &&\n isValid(begins) &&\n isValid(ends) &&\n isSameDay(begins, ends)\n ) {\n return formatDate(begins);\n } else if (begins && ends && isValid(begins) && isValid(ends)) {\n const beginsFormat =\n isSameMonth(begins, ends) && isSameYear(begins, ends)\n ? 'd.'\n : isSameYear(begins, ends)\n ? 'd.M.' // prettier-ignore\n : DATE_FORMAT_FI; // prettier-ignore\n\n return `${format(begins, beginsFormat)}\\u2013${formatDate(ends)}`;\n } else if (begins && isValid(begins)) {\n return formatDate(begins);\n } else if (ends && isValid(ends)) {\n return formatDate(ends);\n } else {\n return '';\n }\n};\n\n/**\n * Formats a date-time range in Finnish date-time format d.M.yyyy H:mm, e.g.\n * 1.1.2020 12:00 - 1.2.2020 12:05\n *\n * If dates are the same, return 1.1.2020 12:00-12:05\n * If only one is given, return it, 1.1.2020 12:00\n *\n * @param begins date object, possibly null\n * @param ends date object, possibly null\n * @return time range as string\n */\nexport const formatDateTimeRange = (\n begins: Date | null | undefined,\n ends: Date | null | undefined\n): string => {\n if (\n begins &&\n ends &&\n isValid(begins) &&\n isValid(ends) &&\n isSameDay(begins, ends)\n ) {\n return `${formatDateTime(begins)}\\u2013${formatTime(ends)}`;\n } else if (begins && ends && isValid(begins) && isValid(ends)) {\n return `${formatDateTime(begins)} \\u2013 ${formatDateTime(ends)}`;\n } else if (begins && isValid(begins)) {\n return formatDateTime(begins);\n } else if (ends && isValid(ends)) {\n return formatDateTime(ends);\n } else {\n return '';\n }\n};\n\n/**\n * Subtracts one minute from date if it is midnight (d.M.yyyy 00:00)\n *\n * If date is e.g. 2.2.2021 00:00, return 1.2.2021 23:59\n * If date is e.g. 2.2.2021 12:00, return 2.2.2021 12:00\n *\n * @param date date object, possibly null\n * @return time as string\n */\nexport const formatMidnight = (date: Date | null | undefined): string => {\n if (!date) {\n return '';\n }\n if (date.getTime() === startOfDay(date).getTime()) {\n return formatDateTime(subMinutes(date, 1));\n } else {\n return formatDateTime(date);\n }\n};\n\n/**\n * Formats price in European price format EUR,cc €, e.g.\n * 20,50 €\n *\n * If price have desimals, return 20,50 €\n * If there are no decimals, return 20€\n *\n * @param price number, possibly null\n * @return price as string or undefined\n */\n\nexport const formatPrice = (\n price: number | null | undefined\n): string | undefined => {\n if (price && price % 1 !== 0) {\n return price?.toLocaleString('fi-FI', {\n style: 'currency',\n currency: 'EUR'\n });\n } else {\n return price?.toLocaleString('fi-FI', {\n style: 'currency',\n currency: 'EUR',\n maximumFractionDigits: 0,\n minimumFractionDigits: 0\n });\n }\n};\n\nexport const fakeDateFromWeekday = (\n weekday: number | undefined\n): Date | undefined => {\n if (weekday != null) {\n return setISODay(new Date(), weekday);\n } else {\n return undefined;\n }\n};\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{attrs:{\"id\":\"app\"}},[_c('router-view')],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\n \n \n
\n\n\n\n","import mod from \"-!../node_modules/thread-loader/dist/cjs.js!../node_modules/babel-loader/lib/index.js!../node_modules/ts-loader/index.js??clonedRuleSet-41.use[2]!../node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./App.vue?vue&type=script&lang=ts\"; export default mod; export * from \"-!../node_modules/thread-loader/dist/cjs.js!../node_modules/babel-loader/lib/index.js!../node_modules/ts-loader/index.js??clonedRuleSet-41.use[2]!../node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./App.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./App.vue?vue&type=template&id=99e87134\"\nimport script from \"./App.vue?vue&type=script&lang=ts\"\nexport * from \"./App.vue?vue&type=script&lang=ts\"\n\n\n/* normalize component */\nimport normalizer from \"!../node_modules/@vue/vue-loader-v15/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('Header',{staticClass:\"header-desktop\"}),_c('MobileHeader',{staticClass:\"header-mobile\"}),(_vm.isLoading)?_c('div',[_c('section',{staticClass:\"skeleton-wrapper\"},[_c('div',{staticClass:\"skeleton-content-wrapper\"},[_c('b-skeleton',{attrs:{\"width\":\"100%\",\"height\":\"3rem\",\"animated\":true}}),_c('b-skeleton',{attrs:{\"width\":\"100%\",\"height\":\"20rem\",\"animated\":true}})],1),_c('div',{staticClass:\"registration-box-skeleton card\"},[_c('b-skeleton',{attrs:{\"width\":\"100%\",\"height\":\"3rem\",\"animated\":true}}),_c('b-skeleton',{attrs:{\"width\":\"100%\",\"height\":\"10rem\",\"animated\":true}})],1)])]):_vm._e(),(!_vm.isLoading && _vm.course)?_c('div',{staticClass:\"wrapper\"},[_c('section',{staticClass:\"main-content content\"},[_c('h1',{staticClass:\"title course-title\",domProps:{\"innerHTML\":_vm._s(_vm.course.name)}}),(_vm.tenantName)?_c('h6',{staticClass:\"title is-6 title-info\"},[_c('router-link',{staticClass:\"is-primary\",attrs:{\"to\":{\n path: (\"/\" + _vm.language + \"/search?serviceproviders=\" + (_vm.course.tenant))\n }}},[_c('span',{staticClass:\"course-tenant\"},[_vm._v(_vm._s(_vm.tenantName))])]),(_vm.course.teacher)?_c('div',{staticClass:\"dot\"}):_vm._e(),_vm._v(\" \"+_vm._s(_vm.course.teacher)+\" \")],1):_vm._e(),_c('div',{staticClass:\"description\",domProps:{\"innerHTML\":_vm._s(_vm.course.description)}}),_c('hr'),_vm._l((_vm.sortBy(['begins', 'ends'], _vm.course.periods)),function(period){return _c('div',{key:period.name + period.begins},[(period.keywords.some(function (keyword) { return keyword.includes('period'); }))?_c('LessonsCollapse',{attrs:{\"period\":period}}):_vm._e()],1)}),(_vm.course.periods.length === 0 && _vm.course.lessons.length > 0)?_c('div',[_c('LessonsCollapse',{attrs:{\"course\":_vm.course}})],1):_vm._e(),(_vm.course.periods.length !== 0 || _vm.course.lessons.length !== 0)?_c('hr'):_vm._e(),_c('RegistrationBox',{staticClass:\"registration-box-mobile card\",attrs:{\"course\":_vm.course}}),(_vm.course.location)?_c('div',{staticClass:\"location\"},[_c('b-icon',{attrs:{\"icon\":\"map-marker-outline\"}}),_c('span',[_vm._v(_vm._s([ _vm.course.location.name, _vm.course.location.address, _vm.course.location.city ] .filter(Boolean) .join(', ')))]),_c('span')],1):_vm._e(),(_vm.course.location)?_c('div',[(_vm.course.location.latlon)?_c('CourseMap',{staticClass:\"course-map\",attrs:{\"coordinates\":_vm.course.location.latlon,\"text\":_vm.course.location.name}}):_vm._e()],1):_vm._e()],2),_c('RegistrationBox',{staticClass:\"registration-box-desktop card\",attrs:{\"course\":_vm.course}})],1):_vm._e(),_c('Footer')],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\n\nexport const BASE_PATH = \"https://api.opistopalvelut.fi/v1/demo/fi\".replace(/\\/+$/, \"\");\n\nexport interface ConfigurationParameters {\n basePath?: string; // override base path\n fetchApi?: FetchAPI; // override for fetch implementation\n middleware?: Middleware[]; // middleware to apply before/after fetch requests\n queryParamsStringify?: (params: HTTPQuery) => string; // stringify function for query strings\n username?: string; // parameter for basic security\n password?: string; // parameter for basic security\n apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security\n accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security\n headers?: HTTPHeaders; //header params we want to use on every request\n credentials?: RequestCredentials; //value for the credentials param we want to use on each request\n}\n\nexport class Configuration {\n constructor(private configuration: ConfigurationParameters = {}) {}\n\n set config(configuration: Configuration) {\n this.configuration = configuration;\n }\n\n get basePath(): string {\n return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;\n }\n\n get fetchApi(): FetchAPI | undefined {\n return this.configuration.fetchApi;\n }\n\n get middleware(): Middleware[] {\n return this.configuration.middleware || [];\n }\n\n get queryParamsStringify(): (params: HTTPQuery) => string {\n return this.configuration.queryParamsStringify || querystring;\n }\n\n get username(): string | undefined {\n return this.configuration.username;\n }\n\n get password(): string | undefined {\n return this.configuration.password;\n }\n\n get apiKey(): ((name: string) => string | Promise) | undefined {\n const apiKey = this.configuration.apiKey;\n if (apiKey) {\n return typeof apiKey === 'function' ? apiKey : () => apiKey;\n }\n return undefined;\n }\n\n get accessToken(): ((name?: string, scopes?: string[]) => string | Promise) | undefined {\n const accessToken = this.configuration.accessToken;\n if (accessToken) {\n return typeof accessToken === 'function' ? accessToken : async () => accessToken;\n }\n return undefined;\n }\n\n get headers(): HTTPHeaders | undefined {\n return this.configuration.headers;\n }\n\n get credentials(): RequestCredentials | undefined {\n return this.configuration.credentials;\n }\n}\n\nexport const DefaultConfig = new Configuration();\n\n/**\n * This is the base class for all generated API classes.\n */\nexport class BaseAPI {\n\n private static readonly jsonRegex = new RegExp('^(:?application\\/json|[^;/ \\t]+\\/[^;/ \\t]+[+]json)[ \\t]*(:?;.*)?$', 'i');\n private middleware: Middleware[];\n\n constructor(protected configuration = DefaultConfig) {\n this.middleware = configuration.middleware;\n }\n\n withMiddleware(this: T, ...middlewares: Middleware[]) {\n const next = this.clone();\n next.middleware = next.middleware.concat(...middlewares);\n return next;\n }\n\n withPreMiddleware(this: T, ...preMiddlewares: Array) {\n const middlewares = preMiddlewares.map((pre) => ({ pre }));\n return this.withMiddleware(...middlewares);\n }\n\n withPostMiddleware(this: T, ...postMiddlewares: Array) {\n const middlewares = postMiddlewares.map((post) => ({ post }));\n return this.withMiddleware(...middlewares);\n }\n\n /**\n * Check if the given MIME is a JSON MIME.\n * JSON MIME examples:\n * application/json\n * application/json; charset=UTF8\n * APPLICATION/JSON\n * application/vnd.company+json\n * @param mime - MIME (Multipurpose Internet Mail Extensions)\n * @return True if the given MIME is JSON, false otherwise.\n */\n protected isJsonMime(mime: string | null | undefined): boolean {\n if (!mime) {\n return false;\n }\n return BaseAPI.jsonRegex.test(mime);\n }\n\n protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise {\n const { url, init } = await this.createFetchParams(context, initOverrides);\n const response = await this.fetchApi(url, init);\n if (response && (response.status >= 200 && response.status < 300)) {\n return response;\n }\n throw new ResponseError(response, 'Response returned an error code');\n }\n\n private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) {\n let url = this.configuration.basePath + context.path;\n if (context.query !== undefined && Object.keys(context.query).length !== 0) {\n // only add the querystring to the URL if there are query parameters.\n // this is done to avoid urls ending with a \"?\" character which buggy webservers\n // do not handle correctly sometimes.\n url += '?' + this.configuration.queryParamsStringify(context.query);\n }\n\n const headers = Object.assign({}, this.configuration.headers, context.headers);\n Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {});\n\n const initOverrideFn =\n typeof initOverrides === \"function\"\n ? initOverrides\n : async () => initOverrides;\n\n const initParams = {\n method: context.method,\n headers,\n body: context.body,\n credentials: this.configuration.credentials,\n };\n\n const overriddenInit: RequestInit = {\n ...initParams,\n ...(await initOverrideFn({\n init: initParams,\n context,\n }))\n };\n\n let body: any;\n if (isFormData(overriddenInit.body)\n || (overriddenInit.body instanceof URLSearchParams)\n || isBlob(overriddenInit.body)) {\n body = overriddenInit.body;\n } else if (this.isJsonMime(headers['Content-Type'])) {\n body = JSON.stringify(overriddenInit.body);\n } else {\n body = overriddenInit.body;\n }\n\n const init: RequestInit = {\n ...overriddenInit,\n body\n };\n\n return { url, init };\n }\n\n private fetchApi = async (url: string, init: RequestInit) => {\n let fetchParams = { url, init };\n for (const middleware of this.middleware) {\n if (middleware.pre) {\n fetchParams = await middleware.pre({\n fetch: this.fetchApi,\n ...fetchParams,\n }) || fetchParams;\n }\n }\n let response: Response | undefined = undefined;\n try {\n response = await (this.configuration.fetchApi || fetch)(fetchParams.url, fetchParams.init);\n } catch (e) {\n for (const middleware of this.middleware) {\n if (middleware.onError) {\n response = await middleware.onError({\n fetch: this.fetchApi,\n url: fetchParams.url,\n init: fetchParams.init,\n error: e,\n response: response ? response.clone() : undefined,\n }) || response;\n }\n }\n if (response === undefined) {\n if (e instanceof Error) {\n throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response');\n } else {\n throw e;\n }\n }\n }\n for (const middleware of this.middleware) {\n if (middleware.post) {\n response = await middleware.post({\n fetch: this.fetchApi,\n url: fetchParams.url,\n init: fetchParams.init,\n response: response.clone(),\n }) || response;\n }\n }\n return response;\n }\n\n /**\n * Create a shallow clone of `this` by constructing a new instance\n * and then shallow cloning data members.\n */\n private clone(this: T): T {\n const constructor = this.constructor as any;\n const next = new constructor(this.configuration);\n next.middleware = this.middleware.slice();\n return next;\n }\n};\n\nfunction isBlob(value: any): value is Blob {\n return typeof Blob !== 'undefined' && value instanceof Blob;\n}\n\nfunction isFormData(value: any): value is FormData {\n return typeof FormData !== \"undefined\" && value instanceof FormData;\n}\n\nexport class ResponseError extends Error {\n override name: \"ResponseError\" = \"ResponseError\";\n constructor(public response: Response, msg?: string) {\n super(msg);\n }\n}\n\nexport class FetchError extends Error {\n override name: \"FetchError\" = \"FetchError\";\n constructor(public cause: Error, msg?: string) {\n super(msg);\n }\n}\n\nexport class RequiredError extends Error {\n override name: \"RequiredError\" = \"RequiredError\";\n constructor(public field: string, msg?: string) {\n super(msg);\n }\n}\n\nexport const COLLECTION_FORMATS = {\n csv: \",\",\n ssv: \" \",\n tsv: \"\\t\",\n pipes: \"|\",\n};\n\nexport type FetchAPI = WindowOrWorkerGlobalScope['fetch'];\n\nexport type Json = any;\nexport type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';\nexport type HTTPHeaders = { [key: string]: string };\nexport type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery };\nexport type HTTPBody = Json | FormData | URLSearchParams;\nexport type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody };\nexport type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original';\n\nexport type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise\n\nexport interface FetchParams {\n url: string;\n init: RequestInit;\n}\n\nexport interface RequestOpts {\n path: string;\n method: HTTPMethod;\n headers: HTTPHeaders;\n query?: HTTPQuery;\n body?: HTTPBody;\n}\n\nexport function querystring(params: HTTPQuery, prefix: string = ''): string {\n return Object.keys(params)\n .map(key => querystringSingleKey(key, params[key], prefix))\n .filter(part => part.length > 0)\n .join('&');\n}\n\nfunction querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string {\n const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);\n if (value instanceof Array) {\n const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue)))\n .join(`&${encodeURIComponent(fullKey)}=`);\n return `${encodeURIComponent(fullKey)}=${multiValue}`;\n }\n if (value instanceof Set) {\n const valueAsArray = Array.from(value);\n return querystringSingleKey(key, valueAsArray, keyPrefix);\n }\n if (value instanceof Date) {\n return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;\n }\n if (value instanceof Object) {\n return querystring(value as HTTPQuery, fullKey);\n }\n return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;\n}\n\nexport function mapValues(data: any, fn: (item: any) => any) {\n return Object.keys(data).reduce(\n (acc, key) => ({ ...acc, [key]: fn(data[key]) }),\n {}\n );\n}\n\nexport function canConsumeForm(consumes: Consume[]): boolean {\n for (const consume of consumes) {\n if ('multipart/form-data' === consume.contentType) {\n return true;\n }\n }\n return false;\n}\n\nexport interface Consume {\n contentType: string;\n}\n\nexport interface RequestContext {\n fetch: FetchAPI;\n url: string;\n init: RequestInit;\n}\n\nexport interface ResponseContext {\n fetch: FetchAPI;\n url: string;\n init: RequestInit;\n response: Response;\n}\n\nexport interface ErrorContext {\n fetch: FetchAPI;\n url: string;\n init: RequestInit;\n error: unknown;\n response?: Response;\n}\n\nexport interface Middleware {\n pre?(context: RequestContext): Promise;\n post?(context: ResponseContext): Promise;\n onError?(context: ErrorContext): Promise;\n}\n\nexport interface ApiResponse {\n raw: Response;\n value(): Promise;\n}\n\nexport interface ResponseTransformer {\n (json: any): T;\n}\n\nexport class JSONApiResponse {\n constructor(public raw: Response, private transformer: ResponseTransformer = (jsonValue: any) => jsonValue) {}\n\n async value(): Promise {\n return this.transformer(await this.raw.json());\n }\n}\n\nexport class VoidApiResponse {\n constructor(public raw: Response) {}\n\n async value(): Promise {\n return undefined;\n }\n}\n\nexport class BlobApiResponse {\n constructor(public raw: Response) {}\n\n async value(): Promise {\n return await this.raw.blob();\n };\n}\n\nexport class TextApiResponse {\n constructor(public raw: Response) {}\n\n async value(): Promise {\n return await this.raw.text();\n };\n}\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\n\n/**\n * Default catalog courses sorting order\n * @export\n */\nexport const CourseSortOrder = {\n Code: 'code',\n Name: 'name',\n Date: 'date',\n Datedesc: 'datedesc'\n} as const;\nexport type CourseSortOrder = typeof CourseSortOrder[keyof typeof CourseSortOrder];\n\n\nexport function CourseSortOrderFromJSON(json: any): CourseSortOrder {\n return CourseSortOrderFromJSONTyped(json, false);\n}\n\nexport function CourseSortOrderFromJSONTyped(json: any, ignoreDiscriminator: boolean): CourseSortOrder {\n return json as CourseSortOrder;\n}\n\nexport function CourseSortOrderToJSON(value?: CourseSortOrder | null): any {\n return value as any;\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\nimport { mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface Geopoint\n */\nexport interface Geopoint {\n [key: string]: any | any;\n /**\n * Latitude\n * @type {number}\n * @memberof Geopoint\n */\n lat: number;\n /**\n * Longitude\n * @type {number}\n * @memberof Geopoint\n */\n lon: number;\n}\n\n/**\n * Check if a given object implements the Geopoint interface.\n */\nexport function instanceOfGeopoint(value: object): boolean {\n if (!('lat' in value)) return false;\n if (!('lon' in value)) return false;\n return true;\n}\n\nexport function GeopointFromJSON(json: any): Geopoint {\n return GeopointFromJSONTyped(json, false);\n}\n\nexport function GeopointFromJSONTyped(json: any, ignoreDiscriminator: boolean): Geopoint {\n if (json == null) {\n return json;\n }\n return {\n \n ...json,\n 'lat': json['lat'],\n 'lon': json['lon'],\n };\n}\n\nexport function GeopointToJSON(value?: Geopoint | null): any {\n if (value == null) {\n return value;\n }\n return {\n \n ...value,\n 'lat': value['lat'],\n 'lon': value['lon'],\n };\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\nimport { mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface HellewiAgeLimits\n */\nexport interface HellewiAgeLimits {\n [key: string]: any | any;\n /**\n * \n * @type {number}\n * @memberof HellewiAgeLimits\n */\n minAge?: number;\n /**\n * \n * @type {number}\n * @memberof HellewiAgeLimits\n */\n maxAge?: number;\n}\n\n/**\n * Check if a given object implements the HellewiAgeLimits interface.\n */\nexport function instanceOfHellewiAgeLimits(value: object): boolean {\n return true;\n}\n\nexport function HellewiAgeLimitsFromJSON(json: any): HellewiAgeLimits {\n return HellewiAgeLimitsFromJSONTyped(json, false);\n}\n\nexport function HellewiAgeLimitsFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiAgeLimits {\n if (json == null) {\n return json;\n }\n return {\n \n ...json,\n 'minAge': json['minAge'] == null ? undefined : json['minAge'],\n 'maxAge': json['maxAge'] == null ? undefined : json['maxAge'],\n };\n}\n\nexport function HellewiAgeLimitsToJSON(value?: HellewiAgeLimits | null): any {\n if (value == null) {\n return value;\n }\n return {\n \n ...value,\n 'minAge': value['minAge'],\n 'maxAge': value['maxAge'],\n };\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\nimport { mapValues } from '../runtime';\nimport type { Geopoint } from './Geopoint';\nimport {\n GeopointFromJSON,\n GeopointFromJSONTyped,\n GeopointToJSON,\n} from './Geopoint';\n\n/**\n * \n * @export\n * @interface HellewiLocation\n */\nexport interface HellewiLocation {\n [key: string]: any | any;\n /**\n * Address\n * @type {string}\n * @memberof HellewiLocation\n */\n address?: string;\n /**\n * City\n * @type {string}\n * @memberof HellewiLocation\n */\n city?: string;\n /**\n * ID in Hellewi\n * \n * This is in always included [/locations](#tag/Location) response\n * but never in [/courses](#tag/Course)\n * @type {number}\n * @memberof HellewiLocation\n */\n id?: number;\n /**\n * \n * @type {Geopoint}\n * @memberof HellewiLocation\n */\n latlon?: Geopoint;\n /**\n * Name\n * @type {string}\n * @memberof HellewiLocation\n */\n name: string;\n /**\n * Postal code\n * @type {string}\n * @memberof HellewiLocation\n */\n postalcode?: string;\n /**\n * Keywords that can be used to match course filters\n * @type {Array}\n * @memberof HellewiLocation\n */\n keywords?: Array;\n /**\n * Accessibility from the perspective of general mobility\n * @type {string}\n * @memberof HellewiLocation\n */\n accessibility?: string;\n /**\n * External ID\n * \n * Optional ID that can be used to match the location to\n * an external system instead of auto-increment ID\n * @type {string}\n * @memberof HellewiLocation\n */\n externalid?: string;\n}\n\n/**\n * Check if a given object implements the HellewiLocation interface.\n */\nexport function instanceOfHellewiLocation(value: object): boolean {\n if (!('name' in value)) return false;\n return true;\n}\n\nexport function HellewiLocationFromJSON(json: any): HellewiLocation {\n return HellewiLocationFromJSONTyped(json, false);\n}\n\nexport function HellewiLocationFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiLocation {\n if (json == null) {\n return json;\n }\n return {\n \n ...json,\n 'address': json['address'] == null ? undefined : json['address'],\n 'city': json['city'] == null ? undefined : json['city'],\n 'id': json['id'] == null ? undefined : json['id'],\n 'latlon': json['latlon'] == null ? undefined : GeopointFromJSON(json['latlon']),\n 'name': json['name'],\n 'postalcode': json['postalcode'] == null ? undefined : json['postalcode'],\n 'keywords': json['keywords'] == null ? undefined : json['keywords'],\n 'accessibility': json['accessibility'] == null ? undefined : json['accessibility'],\n 'externalid': json['externalid'] == null ? undefined : json['externalid'],\n };\n}\n\nexport function HellewiLocationToJSON(value?: HellewiLocation | null): any {\n if (value == null) {\n return value;\n }\n return {\n \n ...value,\n 'address': value['address'],\n 'city': value['city'],\n 'id': value['id'],\n 'latlon': GeopointToJSON(value['latlon']),\n 'name': value['name'],\n 'postalcode': value['postalcode'],\n 'keywords': value['keywords'],\n 'accessibility': value['accessibility'],\n 'externalid': value['externalid'],\n };\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\n\n/**\n * \n * @export\n */\nexport const HellewiTenantType = {\n CommunityCollege: 'COMMUNITY_COLLEGE',\n SportsAndCulture: 'SPORTS_AND_CULTURE',\n ArtsEducation: 'ARTS_EDUCATION',\n SummerSchool: 'SUMMER_SCHOOL',\n FolkHighSchool: 'FOLK_HIGH_SCHOOL',\n VocationalSchool: 'VOCATIONAL_SCHOOL',\n Company: 'COMPANY',\n Association: 'ASSOCIATION',\n Museum: 'MUSEUM',\n EmploymentServices: 'EMPLOYMENT_SERVICES'\n} as const;\nexport type HellewiTenantType = typeof HellewiTenantType[keyof typeof HellewiTenantType];\n\n\nexport function HellewiTenantTypeFromJSON(json: any): HellewiTenantType {\n return HellewiTenantTypeFromJSONTyped(json, false);\n}\n\nexport function HellewiTenantTypeFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiTenantType {\n return json as HellewiTenantType;\n}\n\nexport function HellewiTenantTypeToJSON(value?: HellewiTenantType | null): any {\n return value as any;\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\nimport { mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface HellewiLessonParticipantCount\n */\nexport interface HellewiLessonParticipantCount {\n [key: string]: any | any;\n /**\n * Course ID\n * \n * This is either\n * - a number as string (single-tenant endpoints, e.g. `'3'`)\n * - string with tenant id (in lowercase) and course id number (multi-tenant\n * endpoints, e.g. `'demo.opistopalvelut.fi-3'`)\n * \n * Validation pattern: `^(?:[a-z0-9-.]+-)?[0-9]+$`\n * @type {string}\n * @memberof HellewiLessonParticipantCount\n */\n id: string;\n /**\n * Course is almost full: less than 10% of places available\n * @type {boolean}\n * @memberof HellewiLessonParticipantCount\n */\n almostfull: boolean;\n /**\n * Course is full\n * \n * You might still be able to register for queueing\n * @type {boolean}\n * @memberof HellewiLessonParticipantCount\n */\n full: boolean;\n /**\n * Maximum number of participants\n * @type {number}\n * @memberof HellewiLessonParticipantCount\n */\n max?: number;\n /**\n * Available places for registration\n * @type {number}\n * @memberof HellewiLessonParticipantCount\n */\n available?: number;\n /**\n * How many times course can be added to cart\n * \n * undefined if there is no limit\n * @type {number}\n * @memberof HellewiLessonParticipantCount\n */\n cartlimit?: number;\n /**\n * Minimum number of participants\n * @type {number}\n * @memberof HellewiLessonParticipantCount\n */\n min?: number;\n /**\n * Actual registrations\n * @type {number}\n * @memberof HellewiLessonParticipantCount\n */\n registrations?: number;\n /**\n * Registration is open\n * @type {boolean}\n * @memberof HellewiLessonParticipantCount\n */\n registrationopen: boolean;\n /**\n * Lesson id\n * @type {number}\n * @memberof HellewiLessonParticipantCount\n */\n lessonId: number;\n}\n\n/**\n * Check if a given object implements the HellewiLessonParticipantCount interface.\n */\nexport function instanceOfHellewiLessonParticipantCount(value: object): boolean {\n if (!('id' in value)) return false;\n if (!('almostfull' in value)) return false;\n if (!('full' in value)) return false;\n if (!('registrationopen' in value)) return false;\n if (!('lessonId' in value)) return false;\n return true;\n}\n\nexport function HellewiLessonParticipantCountFromJSON(json: any): HellewiLessonParticipantCount {\n return HellewiLessonParticipantCountFromJSONTyped(json, false);\n}\n\nexport function HellewiLessonParticipantCountFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiLessonParticipantCount {\n if (json == null) {\n return json;\n }\n return {\n \n ...json,\n 'id': json['id'],\n 'almostfull': json['almostfull'],\n 'full': json['full'],\n 'max': json['max'] == null ? undefined : json['max'],\n 'available': json['available'] == null ? undefined : json['available'],\n 'cartlimit': json['cartlimit'] == null ? undefined : json['cartlimit'],\n 'min': json['min'] == null ? undefined : json['min'],\n 'registrations': json['registrations'] == null ? undefined : json['registrations'],\n 'registrationopen': json['registrationopen'],\n 'lessonId': json['lessonId'],\n };\n}\n\nexport function HellewiLessonParticipantCountToJSON(value?: HellewiLessonParticipantCount | null): any {\n if (value == null) {\n return value;\n }\n return {\n \n ...value,\n 'id': value['id'],\n 'almostfull': value['almostfull'],\n 'full': value['full'],\n 'max': value['max'],\n 'available': value['available'],\n 'cartlimit': value['cartlimit'],\n 'min': value['min'],\n 'registrations': value['registrations'],\n 'registrationopen': value['registrationopen'],\n 'lessonId': value['lessonId'],\n };\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\nimport { mapValues } from '../runtime';\nimport type { HellewiLessonParticipantCount } from './HellewiLessonParticipantCount';\nimport {\n HellewiLessonParticipantCountFromJSON,\n HellewiLessonParticipantCountFromJSONTyped,\n HellewiLessonParticipantCountToJSON,\n} from './HellewiLessonParticipantCount';\nimport type { HellewiLocation } from './HellewiLocation';\nimport {\n HellewiLocationFromJSON,\n HellewiLocationFromJSONTyped,\n HellewiLocationToJSON,\n} from './HellewiLocation';\n\n/**\n * \n * @export\n * @interface HellewiCourseLesson\n */\nexport interface HellewiCourseLesson {\n [key: string]: any | any;\n /**\n * Lesson ID\n * \n * Used when adding lessons to cart, and registering to them\n * @type {number}\n * @memberof HellewiCourseLesson\n */\n id: number;\n /**\n * Lesson begins at\n * @type {Date}\n * @memberof HellewiCourseLesson\n */\n begins?: Date;\n /**\n * Lesson ends at\n * @type {Date}\n * @memberof HellewiCourseLesson\n */\n ends?: Date;\n /**\n * \n * @type {HellewiLocation}\n * @memberof HellewiCourseLesson\n */\n location?: HellewiLocation;\n /**\n * \n * @type {HellewiLessonParticipantCount}\n * @memberof HellewiCourseLesson\n */\n participantcount?: HellewiLessonParticipantCount;\n}\n\n/**\n * Check if a given object implements the HellewiCourseLesson interface.\n */\nexport function instanceOfHellewiCourseLesson(value: object): boolean {\n if (!('id' in value)) return false;\n return true;\n}\n\nexport function HellewiCourseLessonFromJSON(json: any): HellewiCourseLesson {\n return HellewiCourseLessonFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseLessonFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourseLesson {\n if (json == null) {\n return json;\n }\n return {\n \n ...json,\n 'id': json['id'],\n 'begins': json['begins'] == null ? undefined : (new Date(json['begins'])),\n 'ends': json['ends'] == null ? undefined : (new Date(json['ends'])),\n 'location': json['location'] == null ? undefined : HellewiLocationFromJSON(json['location']),\n 'participantcount': json['participantcount'] == null ? undefined : HellewiLessonParticipantCountFromJSON(json['participantcount']),\n };\n}\n\nexport function HellewiCourseLessonToJSON(value?: HellewiCourseLesson | null): any {\n if (value == null) {\n return value;\n }\n return {\n \n ...value,\n 'id': value['id'],\n 'begins': value['begins'] == null ? undefined : ((value['begins']).toISOString()),\n 'ends': value['ends'] == null ? undefined : ((value['ends']).toISOString()),\n 'location': HellewiLocationToJSON(value['location']),\n 'participantcount': HellewiLessonParticipantCountToJSON(value['participantcount']),\n };\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\n\n/**\n * \n * @export\n */\nexport const HellewiCatalogItemType = {\n Category: 'category',\n Categorysubject: 'categorysubject',\n Classification: 'classification',\n Coursetype: 'coursetype',\n Department: 'department',\n Educationsector: 'educationsector',\n Educationtype: 'educationtype',\n Language: 'language',\n Levelofstudy: 'levelofstudy',\n Location: 'location',\n Locationgroup: 'locationgroup',\n Period: 'period',\n Subject: 'subject',\n Tag: 'tag',\n Tenant: 'tenant',\n Teachingformat: 'teachingformat',\n Term: 'term',\n Unit: 'unit',\n Weekday: 'weekday',\n Date: 'date',\n Dateinput: 'dateinput',\n Coursesbeginning: 'coursesbeginning',\n Registrationopen: 'registrationopen'\n} as const;\nexport type HellewiCatalogItemType = typeof HellewiCatalogItemType[keyof typeof HellewiCatalogItemType];\n\n\nexport function HellewiCatalogItemTypeFromJSON(json: any): HellewiCatalogItemType {\n return HellewiCatalogItemTypeFromJSONTyped(json, false);\n}\n\nexport function HellewiCatalogItemTypeFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCatalogItemType {\n return json as HellewiCatalogItemType;\n}\n\nexport function HellewiCatalogItemTypeToJSON(value?: HellewiCatalogItemType | null): any {\n return value as any;\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\m), will return all courses ordered by distance, courses farther than this distance will be ranked considerably lower (but if only this filter is used, value can be anything) distancefrom must be given if either filter is used. Only less than operator `:<` is supported for distancehard and distancesoft. For example: `?q=distancefrom:60.169,24.944+distancehard:<50km+distancesoft:<10km`: courses that are closer than 50km from 60.169,24.944, ordered by proximity ### Other filters - registrationopen (boolean, only true supported) registration is currently open. See rules in [Registration](#section/Registration). For example: `?q=registrationopen:true`: courses where registration is open currently ### Distance learning (etäopetus) Distance learning courses have a special location `distancelearning`: `?q=location:distancelearning`: only distance learning courses `?q=location:!distancelearning`: only non-distance learning (lähiopetus) courses ### Additional examples `?q=jooga+category:2`: search term \\\"jooga\\\" in category 2 courses `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `?q=jooga+begins:>=2019-01-01` search term \\\"jooga\\\" in courses that begin after or on 1.1.2019 # Registration Deciding whether you can register to a course follows these rules that are compared in order (i.e. when a rule matches, the rest are not evaluated): 1. current time < course.registrationbegins: **registration IS NOT open**
Registration is not yet started. 2. course.ends < current time: **registration IS NOT open**
Course has already ended. If course ending time is not defined, this step is skipped. 3. current time < course.registrationendshard: **registration IS open**
Registration is not yet ended. 4. otherwise: **registration IS NOT open** Admin interface has only one time for registration ending. It also has a global setting for making that ending time either a soft or hard deadline. API registrationendshard takes this global setting into account (it will be null if registrationends is a soft deadline). Also, if registration beginning or ending time is undefined in admin interface, they will be null in API (i.e. registrationbegins null => registration not open, registrationends null => registration is open). ## Registration to lessons Some courses can have registration to single or multiple lessons in addition to registration to the whole course. Registering to lessons can be enabled from admin interface, and is possible if registration to the course is open, and if there is available places in that lesson. Selecting a price means that registration is for the whole course, where selecting lessons means that registration is only for the specified lessons. Both options are not always present, they follow these rules: 1. If course has registration to lessons (\\\"registration practice\\\" / \\\"ilmoittautumistapa: ilmoittautuminen kerroille\\\") and lessons defined, lessons can be selected. 2. If registration to lessons is restricted (\\\"lesson registration limit\\\" / \\\"kuinka monelle seuraavalle kerralle voi ilmoittautua\\\"), prices cannot be selected. 3. If registration to lessons doesn\\'t cost anything (\\\"single lesson fee\\\" / \\\"kertamaksu\\\" 0,00 e) and all course prices are also zero, prices (and lessons) can be selected. 4. If registration to lessons cost something and all course prices are *not* zero, prices (and lessons) can be selected. 5. If course doesn\\'t have any prices and registration to lessons is free, leaving lessons empty is also allowed, which means that the registration is for the whole course. Note that even when prices and lessons are both selectable, user cannot select both at the same time. Registration to lessons\\' spare places is not possible. ## Selecting installments Prices can have one or more installment groups that can be selected as payment option. Installment options can also expire so that for example course has separate installments for fall and spring period, and fall installment is only valid until the change of period. Course can have prices with installments and prices without installments at the same time. If a course price has installments, selecting one is required. ## How price is calculated 1. Lessons selected: price will be the price of combined lessons 2. Spare place: price for a spare place course is always zero 3. Installments selected: price that can or has to be paid after registration will be the price of the first installment, other installments will be billed later 4. Otherwise: price will be the selected price # Rate limit Requests to API are rate limited to 100 requests per 10 seconds. When this rate limit is exceeded, API will respond with HTTP status code 429 too many requests. # JWT authentication Required fields for header are: - `typ` must always be \\'JWT\\' - `alg` JWT signing algorithm, supported algorithms are: \\'HS256\\', \\'HS384\\' and \\'HS512\\' - `kid` API key (*not* secret), \\'demo\\' can be used for testing with demo data Required fields for payload are: - `sub` subject, must be \\'hellewi-api-v1\\' for this API - `iat` issued at (unix timestamp) - `exp` expiration time (unix timestamp). Maximum expiration time is one week in the future. When using key id \\'demo\\', this is not enforced. - `tenant` tenant identifier, this is in format `.`, e.g. for opistopalvelut.fi/demo tenant is demo.opistopalvelut.fi - `jti` JWT id, unique identifier, used for identifying sessions. This must be a random string. More information about JWTs and an excellent tool for generating JWT tokens for testing can be found at [jwt.io](https://jwt.io). JWT formatting can be tested against [JWT status endpoint](#operation/GetStatusJwt) For simple authentication testing, here is a ready-made JWT: Header: ```json { \\\"alg\\\": \\\"HS256\\\", \\\"typ\\\": \\\"JWT\\\", \\\"kid\\\": \\\"demo\\\" } ``` Payload: ```json { \\\"iat\\\": 1516239022, \\\"exp\\\": 2524608000, \\\"sub\\\": \\\"hellewi-api-v1\\\", \\\"tenant\\\": \\\"demo.opistopalvelut.fi\\\", \\\"jti\\\": \\\"ahtu0aiWo4aMooshie9waethae7cuaj0ua2uichieshaevee3j\\\" } ``` Secret: `salasana` Encoded (linefeeds added): ```markup eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1 MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktYXBpLXYxIiwidGVuYW50IjoiZGVtby5vcGl zdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFodHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2 N1YWowdWEydWljaGllc2hhZXZlZTNqIiwiZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7Vm LCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g ``` Shell command: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" https://api.opistopalvelut.fi/v1/demo/fi/status/jwt ``` # HMAC request signing JWT authentication is used on server to server communication, but sometimes there is a need for authenticating requests that originate from user\\'s browser, such as viewing previously done registrations. Note that the signed request links must be generated in a backend service as the signing uses api secret which must not be given to users. Fields used for HMAC calculation, example from [GetStatusHmac](#operation/GetStatusHmac): - all request parameters *except* `hmac`: - `reqid`: random UUIDv4 string, e.g. \\'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d\\' - `expiry`: expiration time in ISO8601 format, e.g. \\'2023-06-15T06:00:00Z\\' - there probably are also other parameters, depending on the endpoint - two additional parameters that are *not* in the actual request: - `scope`: endpoint HMAC scope, this is show in each endpoint\\'s authorizations-section and start with \\'hmac-\\', e.g. \\'hmac-status-required\\' - `tenant`: same tenant string as is used in JWT authentication, e.g. \\'demo.opistopalvelut.fi\\' All listed parameters are then ordered alphabetically and url-encoded as if they were normal query parameters (linefeed added): ```markup expiry=2023-06-15T06%3A00%3A00Z&reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d& scope=hmac-status-required&tenant=demo.opistopalvelut.fi ``` Then HMAC digest is calculated with SHA-256 using api secret. Above with secret `salasana`: ```markup 88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` This is used as the request `hmac` parameter value. So after all the request is (linefeeds added): ```markup https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a ``` HMAC can be tested against [HMAC status endpoint](#operation/GetStatusHmac). JWT must be used there as well: ```bash curl -v -H \\\"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV CIsImtpZCI6ImRlbW8ifQ.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6ImhlbGxld2ktY XBpLXYxIiwidGVuYW50IjoiZGVtby5vcGlzdG9wYWx2ZWx1dC5maSIsImp0aSI6ImFo dHUwYWlXbzRhTW9vc2hpZTl3YWV0aGFlN2N1YWowdWEydWljaGllc2hhZXZlZTNqIiw iZXhwIjoyNTI0NjA4MDAwfQ.BhzoUPL7VmLCsrtTaZ2yyPIljYNZEiUyoayqRYchm3g\\\" \\\"https://api.opistopalvelut.fi/v1/demo/fi/status/hmac ?expiry=2023-06-15T06%3A00%3A00Z &reqid=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d &hmac=88290d424fa7bc11afc22140346ba3f3fa0552bff121fb6fb63c60deec7b796a\\\" ``` ## Node.js implementation Uses `date-fns` and `uuid` external libraries, and node.js `crypto`. ```javascript import { createHmac } from \\'crypto\\'; import { addYears } from \\'date-fns\\'; import { v4 as uuidv4 } from \\'uuid\\'; const HMAC_ALGORITHM = \\'sha256\\'; const API_SECRET = \\'salasana\\'; // use proper secret handling const queryParamsWithoutHmac = { // use shorter expiration expiry: addYears(new Date(), 2).toISOString(), reqid: uuidv4() }; const hmacCalculationParams = { ...queryParamsWithoutHmac, scope: \\'hmac-status-required\\', tenant: \\'demo.opistopalvelut.fi\\' }; const hmacCalculationURLSearchParams = new URLSearchParams( hmacCalculationParams ); hmacCalculationURLSearchParams.sort(); const hmac = createHmac(HMAC_ALGORITHM, API_SECRET) .update(hmacCalculationURLSearchParams.toString()) .digest(\\'hex\\'); const queryParams = { ...queryParamsWithoutHmac, hmac }; const urlSearchParams = new URLSearchParams(queryParams); console.log(queryParams); console.log(urlSearchParams.toString()); ``` Prints out: ```markup { reqid: \\'09d1eb20-1b84-4af6-935b-6de0db0b3e75\\', expiry: \\'2024-01-05T10:32:50.646Z\\', hmac: \\'27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987\\' } reqid=09d1eb20-1b84-4af6-935b-6de0db0b3e75&expiry=2024-01-05T10%3A32%3A50.646Z&hmac=27d7d2d4136f9e4962a6058296864f15985f81086d145ae687075ce60510c987 ``` \n *\n * The version of the OpenAPI document: 0.1.0\n * Contact: perttu.tikka@hellewi.fi\n *\n * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).\n * https://openapi-generator.tech\n * Do not edit the class manually.\n */\n\nimport { mapValues } from '../runtime';\nimport type { HellewiCatalogItemType } from './HellewiCatalogItemType';\nimport {\n HellewiCatalogItemTypeFromJSON,\n HellewiCatalogItemTypeFromJSONTyped,\n HellewiCatalogItemTypeToJSON,\n} from './HellewiCatalogItemType';\n\n/**\n * \n * @export\n * @interface HellewiCatalogItem\n */\nexport interface HellewiCatalogItem {\n [key: string]: any | any;\n /**\n * \n * @type {HellewiCatalogItemType}\n * @memberof HellewiCatalogItem\n */\n type: HellewiCatalogItemType;\n /**\n * Hellewi ID\n * @type {number}\n * @memberof HellewiCatalogItem\n */\n id?: number;\n /**\n * Keywords that can be used to match filters\n * @type {Array}\n * @memberof HellewiCatalogItem\n */\n keywords?: Array;\n /**\n * Parent keyword\n * @type {string}\n * @memberof HellewiCatalogItem\n */\n parent?: string;\n /**\n * Color\n * @type {string}\n * @memberof HellewiCatalogItem\n */\n color?: string;\n /**\n * Name\n * @type {string}\n * @memberof HellewiCatalogItem\n */\n name: string;\n /**\n * Sorting order\n * @type {number}\n * @memberof HellewiCatalogItem\n */\n sort?: number;\n /**\n * Course count\n * \n * How many courses have this catalog item with current search parameters.\n * This attribute is present only in [Catalog](#operation/Catalog) endpoint.\n * @type {number}\n * @memberof HellewiCatalogItem\n */\n coursecount?: number;\n /**\n * Translate label\n * \n * Whether the label should be translated in the user interface.\n * @type {boolean}\n * @memberof HellewiCatalogItem\n */\n translatelabel?: boolean;\n}\n\n/**\n * Check if a given object implements the HellewiCatalogItem interface.\n */\nexport function instanceOfHellewiCatalogItem(value: object): boolean {\n if (!('type' in value)) return false;\n if (!('name' in value)) return false;\n return true;\n}\n\nexport function HellewiCatalogItemFromJSON(json: any): HellewiCatalogItem {\n return HellewiCatalogItemFromJSONTyped(json, false);\n}\n\nexport function HellewiCatalogItemFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCatalogItem {\n if (json == null) {\n return json;\n }\n return {\n \n ...json,\n 'type': HellewiCatalogItemTypeFromJSON(json['type']),\n 'id': json['id'] == null ? undefined : json['id'],\n 'keywords': json['keywords'] == null ? undefined : json['keywords'],\n 'parent': json['parent'] == null ? undefined : json['parent'],\n 'color': json['color'] == null ? undefined : json['color'],\n 'name': json['name'],\n 'sort': json['sort'] == null ? undefined : json['sort'],\n 'coursecount': json['coursecount'] == null ? undefined : json['coursecount'],\n 'translatelabel': json['translatelabel'] == null ? undefined : json['translatelabel'],\n };\n}\n\nexport function HellewiCatalogItemToJSON(value?: HellewiCatalogItem | null): any {\n if (value == null) {\n return value;\n }\n return {\n \n ...value,\n 'type': HellewiCatalogItemTypeToJSON(value['type']),\n 'id': value['id'],\n 'keywords': value['keywords'],\n 'parent': value['parent'],\n 'color': value['color'],\n 'name': value['name'],\n 'sort': value['sort'],\n 'coursecount': value['coursecount'],\n 'translatelabel': value['translatelabel'],\n };\n}\n\n","/* tslint:disable */\n/* eslint-disable */\n/**\n * API\n * This document specifies the application programming interface (API) for Hellewi. # URL format `https://api.////` e.g. `https://api.opistopalvelut.fi/v1/demo/fi/courses` - protocol: `https` ssl must be used. - domain: `opistopalvelut.fi` domain should be the same as with tenant\\'s admin and registration domain (i.e. not necessarily opistopalvelut.fi). - version: `v1` marks the API version, only v1 is supported. - tenant: `demo` is the tenant name, should be the same as with admin/registration url - language: `fi` is language selection, options fi/en/sv are supported - endpoint: `courses` api endpoint Tenant must be given also inside [JWT](#section/Authentication/JWT), and it must match the tenant/domain in URL. ## Multi-tenant request `https://api.linnunrata.fi///` e.g. `https://api.linnunrata.fi/v1/fi/courses` This will search for courses from all the tenants that the used api key can access. All endpoints do not support multi-tenancy, those that do are listed under tag [MultiTenant](#tag/MultiTenant). # Testing API - url: `https://api.opistopalvelut.fi/v1/demo/fi/` - api key: `demo` - secret: `salasana` Testing API can access only the demo tenant (\\\"database\\\" or \\\"client\\\"). You can however access multiple tenants with the same API key depending on your license. # Search Search query API follows [GitHub Search](https://developer.github.com/v3/search) closely. Search string is in format `?q=SEARCH_TERM_1+SEARCH_TERM_N+FILTER_1+FILTER_N`, e.g. search terms and filters combined with `+` signs or url-encoded spaces `%20`. Search terms are keywords to be searched. Disallowed characters are: `: + \\\" \\'`. Results are sorted by default based on matching: best matching entries first. ### Filters Filters are in format `field:value`. In this simplest case, the field must be equal to the given value. If there are multiple filters defined, results must match *all* different filters. If there are multiple filter values for the same field, results must match *one* of those. For example: `?q=department:3+subject:1+subject:2` means that all courses with department 3 and subject 1 or 2. ### Filter operators Supported operators in filters: - `:` equality, for example: `subject:1` - `:!` not, for example: `department:!2` - `:<` less than, for example: `distancesoft:<10km` - `:<=` less than or equal, for example: `ends:<=2020-02-01` - `:>` greater than, for example: `begins:>2019-01-01` - `:>=` greater than or equal, for example: `begins:>=2019-01-01` ## Pagination Pagination is handled with response headers. Unfortunately these are not included in swagger.json due to technical restrictions in the spec generation. ### link `link` follows [RFC5988](https://tools.ietf.org/html/rfc5988#section-5) and [GitHub pagination](https://developer.github.com/v3/guides/traversing-with-pagination/): there are at most four links: - `rel=\\\"first\\\"` gives the first page of results with current filters - `rel=\\\"prev\\\"` previous page - `rel=\\\"next\\\"` next page - `rel=\\\"last\\\"` last page For example (linefeeds added): GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 link: ; rel=\\\"first\\\", ; rel=\\\"prev\\\", ; rel=\\\"next\\\", ; rel=\\\"last\\\" If the query is for the first page, first and prev are omitted. Similarly, if the query is for the last page, last and next are omitted. If there are no results, all links are omitted. The link-header should be used for creating pagination functionality. ### x-total-count `x-total-count` is the total number of items in result set. For example: GET https://api.opistopalvelut.fi/v1/demo/fi/courses?page=5&limit=2 x-total-count: 29 The maximum number here is 10000. If you are expecting a bigger number, or are interested only in the total course count and not the results itself, you should be using [GetCourseCount](#operation/GetCourseCount). ## Course search Field explanations by name can be found from [ListCourses](#operation/ListCourses) response schema. ### Search term Search term matches text in following course fields with relative weights in parenthesis: - name (10) - code (7) - teacher (5) - subject (4) - location (3) - category (2) - description (1) Search terms can have multiple words combined with double quotation marks `\\\"`. For example: `?q=jooga` search term \\\"jooga\\\" (probably in course name) `?q=830107+\\\"dynaaminen jooga\\\"` search terms \\\"830107\\\" and \\\"dynaaminen jooga\\\" ### Equality filters by id - category - classification - department - educationsector - language - levelofstudy - location - moduleparent (also null works) - period - subject - tag - tenant - term - weekday Category can be queried with a path \\\"department/category\\\" and subject with \\\"department/category/subject\\\" or \\\"category/subject\\\". Tenant makes sense only in the context of multi-tenant requests. For example: `?q=department:3+subject:1+subject:2` all courses with department 3 *and* subject 1 *or* 2 `q=weekday:1` courses that have lessons on Monday `q=moduleparent:18` module child courses that have parent course 18 `q=moduleparent:null` all courses that are not module child courses ### Date filters - begins (date-only, YYYY-MM-DD) - ends (date-only, YYYY-MM-DD) - registrationbegins (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendssoft (date-time, YYYY-MM-DDTHH:MM:SSZ) - registrationendshard (date-time, YYYY-MM-DDTHH:MM:SSZ) For example: `?q=begins:>=2019-01-01`: courses that begin after or on 1.1.2019 ### Distance filters - distancefrom (origin coordinates: \\\\,\\\\) - distancehard (distance: \\\\km or \\\\m), if course\\'s location is farther, course will not be included in results - distancesoft (distance: \\\\km or \\\\