{"version":3,"file":"js/app.a56db871.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/ErrorItemType.ts","webpack://linnunrata/./frontend-src/api/models/Geopoint.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCartItemType.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalog.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalogItem.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalogItemType.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalogSettings.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCatalogSettingsEnabledCatalogItemTypes.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseNotificationLabel.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseStatus.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourse.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseCount.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseDay.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseLesson.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseMinimal.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseMinimalParent.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCourseNotification.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePartial.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePeriod.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePrice.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePriceInstallment.ts","webpack://linnunrata/./frontend-src/api/models/HellewiCoursePriceInstallmentInstallments.ts","webpack://linnunrata/./frontend-src/api/models/HellewiLanguage.ts","webpack://linnunrata/./frontend-src/api/models/HellewiLocation.ts","webpack://linnunrata/./frontend-src/api/models/HellewiParticipantCount.ts","webpack://linnunrata/./frontend-src/api/models/PurchaseProductItemType.ts","webpack://linnunrata/./frontend-src/api/models/PurchaseProductType.ts","webpack://linnunrata/./frontend-src/api/models/Weekday.ts","webpack://linnunrata/./frontend-src/api/models/HellewiTag.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?261f","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?d26d","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-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","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` - `:<` 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 ### 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 \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\nconst isBlob = (value: any) => typeof Blob !== 'undefined' && value instanceof Blob;\n\n/**\n * This is the base class for all generated API classes.\n */\nexport class BaseAPI {\n\n private middleware: Middleware[];\n\n constructor(protected configuration = new Configuration()) {\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 protected async request(context: RequestOpts): Promise {\n const { url, init } = this.createFetchParams(context);\n const response = await this.fetchApi(url, init);\n if (response.status >= 200 && response.status < 300) {\n return response;\n }\n throw response;\n }\n\n private createFetchParams(context: RequestOpts) {\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 const body = (context.body instanceof FormData || context.body instanceof URLSearchParams || isBlob(context.body))\n\t ? context.body\n\t : JSON.stringify(context.body);\n\n const headers = Object.assign({}, this.configuration.headers, context.headers);\n const init = {\n method: context.method,\n headers: headers,\n body,\n credentials: this.configuration.credentials\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 = await this.configuration.fetchApi(fetchParams.url, fetchParams.init);\n for (const middleware of this.middleware) {\n if (middleware.post) {\n response = await middleware.post({\n fetch: this.fetchApi,\n url,\n 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\nexport class RequiredError extends Error {\n 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 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 | ((name: string) => string); // parameter for apiKey security\n accessToken?: string | ((name?: string, scopes?: string[]) => string); // 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 get basePath(): string {\n return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;\n }\n\n get fetchApi(): FetchAPI {\n return this.configuration.fetchApi || window.fetch.bind(window);\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) | 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) | undefined {\n const accessToken = this.configuration.accessToken;\n if (accessToken) {\n return typeof accessToken === 'function' ? accessToken : () => 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 type Json = any;\nexport type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS';\nexport type HTTPHeaders = { [key: string]: string };\nexport type HTTPQuery = { [key: string]: string | number | null | boolean | Array | HTTPQuery };\nexport type HTTPBody = Json | FormData | URLSearchParams;\nexport type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original';\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 exists(json: any, key: string) {\n const value = json[key];\n return value !== null && value !== undefined;\n}\n\nexport function querystring(params: HTTPQuery, prefix: string = ''): string {\n return Object.keys(params)\n .map((key) => {\n const fullKey = prefix + (prefix.length ? `[${key}]` : key);\n const value = params[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 Object) {\n return querystring(value as HTTPQuery, fullKey);\n }\n return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;\n })\n .filter(part => part.length > 0)\n .join('&');\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 Middleware {\n pre?(context: RequestContext): Promise;\n post?(context: ResponseContext): 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` - `:<` 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 ### 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 \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 * @export\n * @enum {string}\n */\nexport enum ErrorItemType {\n Missing = 'missing',\n MissingField = 'missingField',\n Invalid = 'invalid',\n AlreadyExists = 'alreadyExists',\n Custom = 'custom'\n}\n\nexport function ErrorItemTypeFromJSON(json: any): ErrorItemType {\n return ErrorItemTypeFromJSONTyped(json, false);\n}\n\nexport function ErrorItemTypeFromJSONTyped(json: any, ignoreDiscriminator: boolean): ErrorItemType {\n return json as ErrorItemType;\n}\n\nexport function ErrorItemTypeToJSON(value?: ErrorItemType | 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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface Geopoint\n */\nexport interface Geopoint {\n [key: string]: object | 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\nexport function GeopointFromJSON(json: any): Geopoint {\n return GeopointFromJSONTyped(json, false);\n}\n\nexport function GeopointFromJSONTyped(json: any, ignoreDiscriminator: boolean): Geopoint {\n if ((json === undefined) || (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 === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'lat': value.lat,\n 'lon': value.lon,\n };\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` - `:<` 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 ### 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 \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 * @export\n * @enum {string}\n */\nexport enum HellewiCartItemType {\n Course = 'course'\n}\n\nexport function HellewiCartItemTypeFromJSON(json: any): HellewiCartItemType {\n return HellewiCartItemTypeFromJSONTyped(json, false);\n}\n\nexport function HellewiCartItemTypeFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCartItemType {\n return json as HellewiCartItemType;\n}\n\nexport function HellewiCartItemTypeToJSON(value?: HellewiCartItemType | 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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCatalogItem,\n HellewiCatalogItemFromJSON,\n HellewiCatalogItemFromJSONTyped,\n HellewiCatalogItemToJSON,\n} from './';\n\n/**\n * Catalog with all different CatalogItems grouped and sorted\n * @export\n * @interface HellewiCatalog\n */\nexport interface HellewiCatalog {\n [key: string]: object | any;\n /**\n * Department These are configurable by tenant, and they usually contain for example the city which organizes the courses (e.g. Tampere, Ylöjärvi, Kuru, Viljakkala). Department, Category and Subject form a tree: a category\\'s parent is always a department (or undefined), and subject\\'s parent is always a category (or undefined).\n * @type {Array}\n * @memberof HellewiCatalog\n */\n department: Array;\n /**\n * Category Higher-level course categorisation. These are for example arts, languages, health and such. These are also configurable by tenant, so different tenant\\'s categories are not comparable with each others. Category can have department as parent, and it can have multiple subjects as children.\n * @type {Array}\n * @memberof HellewiCatalog\n */\n category: Array;\n /**\n * Subject Lower-level course categorisation. These are for example English, French, German under languages-category. Subject\\'s parent is a category (if any).\n * @type {Array}\n * @memberof HellewiCatalog\n */\n subject: Array;\n /**\n * Classification High level classification of courses. These are based on education sectors. These are static for all the tenants, and can be used when combining data from multiple tenants. Education sectors are classified the following way (itcode and educationsector\\'s name): **1: Sports and wellness / Liikunta ja hyvinvointi / Motion och välmående** - 752 Liikunta ja urheilu - 799 Muu sosiaali-, terveys- ja liikunta-alan koulutus - 751 Terveysala ja hammashuolto - 101 Vapaa-aika- ja nuorisotyö **2: Crafts / Käsityö / Hantverk** - 201 Käsi- ja taideteollisuus ja käden taidot - 508 Tekstiili- ja vaatetusala **3: Languages / Kielet / Språk** - 10201 Kielitiede - 10202 Suomi - 10203 Ruotsi - 10204 Englanti - 10205 Saksa - 10206 Ranska - 10207 Venäjä - 10208 Espanja - 10209 Italia - 10299 Muut kielet **4: Music / Musiikki / Musik** - 205 Musiikki **5: Arts / Kuvataide / Bildkonst och formgivning** - 206 Kuvataide **6: Dance and theater / Tanssi ja teatteri / Dans och teater** - 204 Teatteri ja tanssi **7: Technology and business / Tekniikka ja talous / Teknik och ekonomi** - 40201 Tietokoneen ajokorttikoulutus - 40299 Muu tietotekniikan hyväksikäyttö - 504 Tieto- ja tietoliikennetekniikka - 505 Graafinen ja viestintätekniikka - 202 Viestintä- ja informaatioala - 301 Liiketalous ja kauppa - 351 Yrittäjyys ja yrittäjyyskasvatus - 302 Kansantalous - 304 Tilastointi ja tilastotiede - 401 Matematiikka - 451 Fysiikka ja kemia sekä geo-, avaruus- ja tähtitiet - 452 Biologia ja maantiede - 499 Muu luonnontietteiden alan koulutus - 501 Arkkitehtuuri ja rakentaminen - 502 Kone-, metalli- ja energiatekniikka - 503 Sähkö- ja automaatiotekniikka - 506 Elintarvikeala ja biotekniikka - 507 Prosessi-, kemian ja materiaalitekniikka - 509 Ajoneuvo- ja kuljetusala - 510 Tuotantotalous - 599 Muu tekniikan ja liikenteen alan koulutus **8: Society and humanities / Yhteiskunta ja humanismi / Samhälle och humaniora** - 203 Kirjallisuus - 207 Kulttuurin- ja taiteiden tutkimus - 151 Opetus- ja kasvatustyö ja psykologia - 103 Historia ja arkeologia - 199 Muu humanistisen ja kasvatusalan koulutus - 399 Muu yhteiskunnallisten aineiden, liiketalouden ja - 104 Filosofia - 107 Teologia - 305 Sosiaalitieteet - 306 Politiikka ja politiikkatieteet - 307 Oikeuskäytäntö ja oikeustieteet **9: Nature and environment / Luonto ja ympäristö / natur och miljö** - 602 Puutarhatalous ja puutarhanhoito - 605 Luonto- ja ympäristöala - 651 Maatila- ja metsätalous - 603 Kalatalous ja kalastus - 699 Muu luonnonvara- ja ympäristöalan koulutus **10: Food, drink and travel / Ruoka, juoma ja matkailu / Mat, dryck och resor** - 802 Majoitus- ja ravitsemisala sekä ruoan valmistus - 851 Kotitalous- ja kuluttajapalvelut sekä puhdistus - 801 Matkailuala - 899 Muu matkailu-, ravitsemis- ja talousalan koulutus **99: Others / Muut / Övriga** - 999 Muu koulutus - 99 Muu yleissivistävä koulutus - 2 Perusopetus - 3 Lukiokoulutus - 51 Oppimisvalmiuksien kehittäminen ja motivointi - 299 Muu kulttuurialan koulutus - 30301 Kansalais- ja järjestötoiminta - 30399 Muu hallinnon alan koulutus - 701 Sosiaaliala - 753 Farmasia ja muu lääkehuolto sekä tekniset terveysp - 709 Eläinlääketiede - 710 Kauneudenhoitoala - 901 Sotilas- ja rajavartioala - 902 Palo- ja pelastusala - 951 Poliisi- ja vartiointiala\n * @type {Array}\n * @memberof HellewiCatalog\n */\n classification: Array;\n /**\n * Education sector (koulutusala) Lower level course categorisation. This follows the Statistics Finland\\'s [National Classification of Education](https://www.stat.fi/fi/luokitukset/koulutus), although an older version of it. Education sector\\'s parent is a classification\n * @type {Array}\n * @memberof HellewiCatalog\n */\n educationsector: Array;\n /**\n * Level of study These are levels for how courses compare with each others, e.g. beginner, intermediate, advanced. For language courses for example, the level of study can follow CEFR levels A1, A2, B1, etc. These are configurable by the tenant, so different tenant\\'s categories are not comparable with each others.\n * @type {Array}\n * @memberof HellewiCatalog\n */\n levelofstudy: Array;\n /**\n * Language Language used in the course.\n * @type {Array}\n * @memberof HellewiCatalog\n */\n language: Array;\n /**\n * Location Where course is held.\n * @type {Array}\n * @memberof HellewiCatalog\n */\n location: Array;\n /**\n * Term (lukuvuosi) Years in education usually start in the autumn and continue until summer. Term is this time period, usually divided into autumn and spring semesters (catalog item period).\n * @type {Array}\n * @memberof HellewiCatalog\n */\n term: Array;\n /**\n * Period (lukukausi) Courses usually have a certain period during which they are held. There are usually two periods during a term: autumn and spring (syys- ja kevätlukukausi). Period\\'s parent is a term.\n * @type {Array}\n * @memberof HellewiCatalog\n */\n period: Array;\n /**\n * Tag Custom tag for a course, these can be defined by the tenant.\n * @type {Array}\n * @memberof HellewiCatalog\n */\n tag: Array;\n /**\n * Tenant Tenant that is organizing the courses. This makes only in multi-tenant context, in single-tenant there will be only one tenant here.\n * @type {Array}\n * @memberof HellewiCatalog\n */\n tenant: Array;\n /**\n * Weekday On which day(s) the course is held.\n * @type {Array}\n * @memberof HellewiCatalog\n */\n weekday: Array;\n}\n\nexport function HellewiCatalogFromJSON(json: any): HellewiCatalog {\n return HellewiCatalogFromJSONTyped(json, false);\n}\n\nexport function HellewiCatalogFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCatalog {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'department': ((json['department'] as Array).map(HellewiCatalogItemFromJSON)),\n 'category': ((json['category'] as Array).map(HellewiCatalogItemFromJSON)),\n 'subject': ((json['subject'] as Array).map(HellewiCatalogItemFromJSON)),\n 'classification': ((json['classification'] as Array).map(HellewiCatalogItemFromJSON)),\n 'educationsector': ((json['educationsector'] as Array).map(HellewiCatalogItemFromJSON)),\n 'levelofstudy': ((json['levelofstudy'] as Array).map(HellewiCatalogItemFromJSON)),\n 'language': ((json['language'] as Array).map(HellewiCatalogItemFromJSON)),\n 'location': ((json['location'] as Array).map(HellewiCatalogItemFromJSON)),\n 'term': ((json['term'] as Array).map(HellewiCatalogItemFromJSON)),\n 'period': ((json['period'] as Array).map(HellewiCatalogItemFromJSON)),\n 'tag': ((json['tag'] as Array).map(HellewiCatalogItemFromJSON)),\n 'tenant': ((json['tenant'] as Array).map(HellewiCatalogItemFromJSON)),\n 'weekday': ((json['weekday'] as Array).map(HellewiCatalogItemFromJSON)),\n };\n}\n\nexport function HellewiCatalogToJSON(value?: HellewiCatalog | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'department': ((value.department as Array).map(HellewiCatalogItemToJSON)),\n 'category': ((value.category as Array).map(HellewiCatalogItemToJSON)),\n 'subject': ((value.subject as Array).map(HellewiCatalogItemToJSON)),\n 'classification': ((value.classification as Array).map(HellewiCatalogItemToJSON)),\n 'educationsector': ((value.educationsector as Array).map(HellewiCatalogItemToJSON)),\n 'levelofstudy': ((value.levelofstudy as Array).map(HellewiCatalogItemToJSON)),\n 'language': ((value.language as Array).map(HellewiCatalogItemToJSON)),\n 'location': ((value.location as Array).map(HellewiCatalogItemToJSON)),\n 'term': ((value.term as Array).map(HellewiCatalogItemToJSON)),\n 'period': ((value.period as Array).map(HellewiCatalogItemToJSON)),\n 'tag': ((value.tag as Array).map(HellewiCatalogItemToJSON)),\n 'tenant': ((value.tenant as Array).map(HellewiCatalogItemToJSON)),\n 'weekday': ((value.weekday as Array).map(HellewiCatalogItemToJSON)),\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCatalogItemType,\n HellewiCatalogItemTypeFromJSON,\n HellewiCatalogItemTypeFromJSONTyped,\n HellewiCatalogItemTypeToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCatalogItem\n */\nexport interface HellewiCatalogItem {\n [key: string]: object | 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 How many courses have this catalog item with current search parameters. This attribute is present only in [Catalog](#operation/Catalog) endpoint.\n * @type {number}\n * @memberof HellewiCatalogItem\n */\n coursecount?: number;\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 === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'type': HellewiCatalogItemTypeFromJSON(json['type']),\n 'id': !exists(json, 'id') ? undefined : json['id'],\n 'keywords': !exists(json, 'keywords') ? undefined : json['keywords'],\n 'parent': !exists(json, 'parent') ? undefined : json['parent'],\n 'color': !exists(json, 'color') ? undefined : json['color'],\n 'name': json['name'],\n 'sort': !exists(json, 'sort') ? undefined : json['sort'],\n 'coursecount': !exists(json, 'coursecount') ? undefined : json['coursecount'],\n };\n}\n\nexport function HellewiCatalogItemToJSON(value?: HellewiCatalogItem | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\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 };\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` - `:<` 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 ### 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 \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 * @export\n * @enum {string}\n */\nexport enum HellewiCatalogItemType {\n Category = 'category',\n Classification = 'classification',\n Department = 'department',\n Educationsector = 'educationsector',\n Language = 'language',\n Levelofstudy = 'levelofstudy',\n Location = 'location',\n Period = 'period',\n Subject = 'subject',\n Tag = 'tag',\n Tenant = 'tenant',\n Term = 'term',\n Weekday = 'weekday'\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCatalogSettingsEnabledCatalogItemTypes,\n HellewiCatalogSettingsEnabledCatalogItemTypesFromJSON,\n HellewiCatalogSettingsEnabledCatalogItemTypesFromJSONTyped,\n HellewiCatalogSettingsEnabledCatalogItemTypesToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCatalogSettings\n */\nexport interface HellewiCatalogSettings {\n [key: string]: object | any;\n /**\n * \n * @type {HellewiCatalogSettingsEnabledCatalogItemTypes}\n * @memberof HellewiCatalogSettings\n */\n enabledcatalogitemtypes: HellewiCatalogSettingsEnabledCatalogItemTypes;\n}\n\nexport function HellewiCatalogSettingsFromJSON(json: any): HellewiCatalogSettings {\n return HellewiCatalogSettingsFromJSONTyped(json, false);\n}\n\nexport function HellewiCatalogSettingsFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCatalogSettings {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'enabledcatalogitemtypes': HellewiCatalogSettingsEnabledCatalogItemTypesFromJSON(json['enabledcatalogitemtypes']),\n };\n}\n\nexport function HellewiCatalogSettingsToJSON(value?: HellewiCatalogSettings | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'enabledcatalogitemtypes': HellewiCatalogSettingsEnabledCatalogItemTypesToJSON(value.enabledcatalogitemtypes),\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * Settings for showing catalog in user interface\n * @export\n * @interface HellewiCatalogSettingsEnabledCatalogItemTypes\n */\nexport interface HellewiCatalogSettingsEnabledCatalogItemTypes {\n [key: string]: object | any;\n /**\n * Department catalog items should be shown as a single list\n * @type {boolean}\n * @memberof HellewiCatalogSettingsEnabledCatalogItemTypes\n */\n department: boolean;\n /**\n * Category catalog items should be shown as a single list I.e. select only the category catalog items with parent: null\n * @type {boolean}\n * @memberof HellewiCatalogSettingsEnabledCatalogItemTypes\n */\n category: boolean;\n /**\n * Category and subject catalog items should be shown as a tree Categories with parent: null and subjects with each respective category as parent.\n * @type {boolean}\n * @memberof HellewiCatalogSettingsEnabledCatalogItemTypes\n */\n categorysubject: boolean;\n /**\n * Category catalog items should be shown as a single list I.e. select only the category catalog items with parent: null\n * @type {boolean}\n * @memberof HellewiCatalogSettingsEnabledCatalogItemTypes\n */\n subject: boolean;\n /**\n * Location catalog items should be shown as a single list\n * @type {boolean}\n * @memberof HellewiCatalogSettingsEnabledCatalogItemTypes\n */\n location: boolean;\n /**\n * Period catalog items should be shown as a single list\n * @type {boolean}\n * @memberof HellewiCatalogSettingsEnabledCatalogItemTypes\n */\n period: boolean;\n /**\n * Weekday catalog items should be shown as a single list\n * @type {boolean}\n * @memberof HellewiCatalogSettingsEnabledCatalogItemTypes\n */\n weekday: boolean;\n}\n\nexport function HellewiCatalogSettingsEnabledCatalogItemTypesFromJSON(json: any): HellewiCatalogSettingsEnabledCatalogItemTypes {\n return HellewiCatalogSettingsEnabledCatalogItemTypesFromJSONTyped(json, false);\n}\n\nexport function HellewiCatalogSettingsEnabledCatalogItemTypesFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCatalogSettingsEnabledCatalogItemTypes {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'department': json['department'],\n 'category': json['category'],\n 'categorysubject': json['categorysubject'],\n 'subject': json['subject'],\n 'location': json['location'],\n 'period': json['period'],\n 'weekday': json['weekday'],\n };\n}\n\nexport function HellewiCatalogSettingsEnabledCatalogItemTypesToJSON(value?: HellewiCatalogSettingsEnabledCatalogItemTypes | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'department': value.department,\n 'category': value.category,\n 'categorysubject': value.categorysubject,\n 'subject': value.subject,\n 'location': value.location,\n 'period': value.period,\n 'weekday': value.weekday,\n };\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` - `:<` 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 ### 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 \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 * @export\n * @enum {string}\n */\nexport enum HellewiCourseNotificationLabel {\n Success = 'success',\n Danger = 'danger',\n Warning = 'warning',\n Info = 'info'\n}\n\nexport function HellewiCourseNotificationLabelFromJSON(json: any): HellewiCourseNotificationLabel {\n return HellewiCourseNotificationLabelFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseNotificationLabelFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourseNotificationLabel {\n return json as HellewiCourseNotificationLabel;\n}\n\nexport function HellewiCourseNotificationLabelToJSON(value?: HellewiCourseNotificationLabel | 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` - `:<` 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 ### 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 \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 * Course statuses - `NOT_YET_STARTED` Course has not yet started - `IN_PROGRESS` Course is in progress - `ENDED` Course has ended - `CANCELLED` Course has been cancelled (before it started) - `INTERRUPTED` Course has been interrupted (after it started) Currently only one of the statuses can be active at the same time, but it is also possible that none of them are. Statuses can be added in the future, so the field is an array, and implementation cannot make any assumptions that the requested status would be always in index 0.\n * @export\n * @enum {string}\n */\nexport enum HellewiCourseStatus {\n NOTYETSTARTED = 'NOT_YET_STARTED',\n INPROGRESS = 'IN_PROGRESS',\n ENDED = 'ENDED',\n CANCELLED = 'CANCELLED',\n INTERRUPTED = 'INTERRUPTED'\n}\n\nexport function HellewiCourseStatusFromJSON(json: any): HellewiCourseStatus {\n return HellewiCourseStatusFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseStatusFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourseStatus {\n return json as HellewiCourseStatus;\n}\n\nexport function HellewiCourseStatusToJSON(value?: HellewiCourseStatus | 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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCatalogItem,\n HellewiCatalogItemFromJSON,\n HellewiCatalogItemFromJSONTyped,\n HellewiCatalogItemToJSON,\n HellewiCourseDay,\n HellewiCourseDayFromJSON,\n HellewiCourseDayFromJSONTyped,\n HellewiCourseDayToJSON,\n HellewiCourseLesson,\n HellewiCourseLessonFromJSON,\n HellewiCourseLessonFromJSONTyped,\n HellewiCourseLessonToJSON,\n HellewiCourseNotification,\n HellewiCourseNotificationFromJSON,\n HellewiCourseNotificationFromJSONTyped,\n HellewiCourseNotificationToJSON,\n HellewiCoursePartial,\n HellewiCoursePartialFromJSON,\n HellewiCoursePartialFromJSONTyped,\n HellewiCoursePartialToJSON,\n HellewiCoursePeriod,\n HellewiCoursePeriodFromJSON,\n HellewiCoursePeriodFromJSONTyped,\n HellewiCoursePeriodToJSON,\n HellewiCoursePrice,\n HellewiCoursePriceFromJSON,\n HellewiCoursePriceFromJSONTyped,\n HellewiCoursePriceToJSON,\n HellewiCourseStatus,\n HellewiCourseStatusFromJSON,\n HellewiCourseStatusFromJSONTyped,\n HellewiCourseStatusToJSON,\n HellewiLanguage,\n HellewiLanguageFromJSON,\n HellewiLanguageFromJSONTyped,\n HellewiLanguageToJSON,\n HellewiLocation,\n HellewiLocationFromJSON,\n HellewiLocationFromJSONTyped,\n HellewiLocationToJSON,\n HellewiParticipantCount,\n HellewiParticipantCountFromJSON,\n HellewiParticipantCountFromJSONTyped,\n HellewiParticipantCountToJSON,\n HellewiTag,\n HellewiTagFromJSON,\n HellewiTagFromJSONTyped,\n HellewiTagToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCourse\n */\nexport interface HellewiCourse {\n [key: string]: object | any;\n /**\n * Course ID This is either - a number as string (single-tenant endpoints, e.g. `\\'3\\'`) - string with tenant id (in lowercase) and course id number (multi-tenant endpoints, e.g. `\\'demo.opistopalvelut.fi-3\\'`) Validation pattern: `^(?:[a-z0-9-.]+-)?[0-9]+$`\n * @type {string}\n * @memberof HellewiCourse\n */\n id: string;\n /**\n * Code / koodi\n * @type {string}\n * @memberof HellewiCourse\n */\n code?: string;\n /**\n * Name\n * @type {string}\n * @memberof HellewiCourse\n */\n name?: string;\n /**\n * Tenant\n * @type {string}\n * @memberof HellewiCourse\n */\n tenant: string;\n /**\n * Course statuses - `NOT_YET_STARTED` Course has not yet started - `IN_PROGRESS` Course is in progress - `ENDED` Course has ended - `CANCELLED` Course has been cancelled (before it started) - `INTERRUPTED` Course has been interrupted (after it started) Currently only one of the statuses can be active at the same time, but it is also possible that none of them are. Statuses can be added in the future, so the field is an array, and implementation cannot make any assumptions that the requested status would be always in index 0.\n * @type {Array}\n * @memberof HellewiCourse\n */\n statuses: Array;\n /**\n * Course begins on date\n * @type {Date}\n * @memberof HellewiCourse\n */\n begins?: Date;\n /**\n * Course ends on date\n * @type {Date}\n * @memberof HellewiCourse\n */\n ends?: Date;\n /**\n * Registration begins on date/time null means that registration is not open\n * @type {Date}\n * @memberof HellewiCourse\n */\n registrationbegins?: Date;\n /**\n * Registration ends on date/time, soft limit If this time is in the past, registrations are still accepted, but user interfaces should show this field as time when registrations close\n * @type {Date}\n * @memberof HellewiCourse\n */\n registrationendssoft?: Date;\n /**\n * Registration ends on date/time, hard limit null means that registration has no ending limit\n * @type {Date}\n * @memberof HellewiCourse\n */\n registrationendshard?: Date;\n /**\n * Whether registration is open at the moment See rules in [Registration](#section/Registration)\n * @type {boolean}\n * @memberof HellewiCourse\n */\n registrationopen?: boolean;\n /**\n * Teacher\n * @type {string}\n * @memberof HellewiCourse\n */\n teacher?: string;\n /**\n * ECTS credits / opintopisteet\n * @type {number}\n * @memberof HellewiCourse\n */\n ectscredits?: number;\n /**\n * Topical / ajankohtainen This course should be emphasized\n * @type {boolean}\n * @memberof HellewiCourse\n */\n topical?: boolean;\n /**\n * Day(s) / kurssipäivät\n * @type {Array}\n * @memberof HellewiCourse\n */\n days?: Array;\n /**\n * \n * @type {HellewiLocation}\n * @memberof HellewiCourse\n */\n location?: HellewiLocation;\n /**\n * Notification\n * @type {Array}\n * @memberof HellewiCourse\n */\n notifications?: Array;\n /**\n * Periods and terms / lukukaudet ja lukuvuodet\n * @type {Array}\n * @memberof HellewiCourse\n */\n periods?: Array;\n /**\n * \n * @type {HellewiLanguage}\n * @memberof HellewiCourse\n */\n language?: HellewiLanguage;\n /**\n * Tags\n * @type {Array}\n * @memberof HellewiCourse\n */\n tags?: Array;\n /**\n * Prices\n * @type {Array}\n * @memberof HellewiCourse\n */\n prices?: Array;\n /**\n * \n * @type {HellewiCoursePartial}\n * @memberof HellewiCourse\n */\n moduleparent?: HellewiCoursePartial;\n /**\n * Child courses for a module parent course\n * @type {Array}\n * @memberof HellewiCourse\n */\n modulechildren?: Array;\n /**\n * Catalog items Different item types are explained under [GetCatalog](#operation/GetCatalog) response\n * @type {Array}\n * @memberof HellewiCourse\n */\n catalogitems: Array;\n /**\n * \n * @type {HellewiCatalogItem}\n * @memberof HellewiCourse\n */\n department?: HellewiCatalogItem;\n /**\n * \n * @type {HellewiCatalogItem}\n * @memberof HellewiCourse\n */\n category?: HellewiCatalogItem;\n /**\n * \n * @type {HellewiCatalogItem}\n * @memberof HellewiCourse\n */\n subject?: HellewiCatalogItem;\n /**\n * Description\n * @type {string}\n * @memberof HellewiCourse\n */\n description?: string;\n /**\n * Keywords that can be used to match filters\n * @type {Array}\n * @memberof HellewiCourse\n */\n keywords?: Array;\n /**\n * Lessons\n * @type {Array}\n * @memberof HellewiCourse\n */\n lessons?: Array;\n /**\n * \n * @type {HellewiParticipantCount}\n * @memberof HellewiCourse\n */\n participantcount?: HellewiParticipantCount;\n /**\n * Link for course registration\n * @type {string}\n * @memberof HellewiCourse\n */\n registrationlink?: string;\n}\n\nexport function HellewiCourseFromJSON(json: any): HellewiCourse {\n return HellewiCourseFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourse {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'id': json['id'],\n 'code': !exists(json, 'code') ? undefined : json['code'],\n 'name': !exists(json, 'name') ? undefined : json['name'],\n 'tenant': json['tenant'],\n 'statuses': ((json['statuses'] as Array).map(HellewiCourseStatusFromJSON)),\n 'begins': !exists(json, 'begins') ? undefined : (new Date(json['begins'])),\n 'ends': !exists(json, 'ends') ? undefined : (new Date(json['ends'])),\n 'registrationbegins': !exists(json, 'registrationbegins') ? undefined : (new Date(json['registrationbegins'])),\n 'registrationendssoft': !exists(json, 'registrationendssoft') ? undefined : (new Date(json['registrationendssoft'])),\n 'registrationendshard': !exists(json, 'registrationendshard') ? undefined : (new Date(json['registrationendshard'])),\n 'registrationopen': !exists(json, 'registrationopen') ? undefined : json['registrationopen'],\n 'teacher': !exists(json, 'teacher') ? undefined : json['teacher'],\n 'ectscredits': !exists(json, 'ectscredits') ? undefined : json['ectscredits'],\n 'topical': !exists(json, 'topical') ? undefined : json['topical'],\n 'days': !exists(json, 'days') ? undefined : ((json['days'] as Array).map(HellewiCourseDayFromJSON)),\n 'location': !exists(json, 'location') ? undefined : HellewiLocationFromJSON(json['location']),\n 'notifications': !exists(json, 'notifications') ? undefined : ((json['notifications'] as Array).map(HellewiCourseNotificationFromJSON)),\n 'periods': !exists(json, 'periods') ? undefined : ((json['periods'] as Array).map(HellewiCoursePeriodFromJSON)),\n 'language': !exists(json, 'language') ? undefined : HellewiLanguageFromJSON(json['language']),\n 'tags': !exists(json, 'tags') ? undefined : ((json['tags'] as Array).map(HellewiTagFromJSON)),\n 'prices': !exists(json, 'prices') ? undefined : ((json['prices'] as Array).map(HellewiCoursePriceFromJSON)),\n 'moduleparent': !exists(json, 'moduleparent') ? undefined : HellewiCoursePartialFromJSON(json['moduleparent']),\n 'modulechildren': !exists(json, 'modulechildren') ? undefined : ((json['modulechildren'] as Array).map(HellewiCoursePartialFromJSON)),\n 'catalogitems': ((json['catalogitems'] as Array).map(HellewiCatalogItemFromJSON)),\n 'department': !exists(json, 'department') ? undefined : HellewiCatalogItemFromJSON(json['department']),\n 'category': !exists(json, 'category') ? undefined : HellewiCatalogItemFromJSON(json['category']),\n 'subject': !exists(json, 'subject') ? undefined : HellewiCatalogItemFromJSON(json['subject']),\n 'description': !exists(json, 'description') ? undefined : json['description'],\n 'keywords': !exists(json, 'keywords') ? undefined : json['keywords'],\n 'lessons': !exists(json, 'lessons') ? undefined : ((json['lessons'] as Array).map(HellewiCourseLessonFromJSON)),\n 'participantcount': !exists(json, 'participantcount') ? undefined : HellewiParticipantCountFromJSON(json['participantcount']),\n 'registrationlink': !exists(json, 'registrationlink') ? undefined : json['registrationlink'],\n };\n}\n\nexport function HellewiCourseToJSON(value?: HellewiCourse | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'id': value.id,\n 'code': value.code,\n 'name': value.name,\n 'tenant': value.tenant,\n 'statuses': ((value.statuses as Array).map(HellewiCourseStatusToJSON)),\n 'begins': value.begins === undefined ? undefined : (value.begins.toISOString().substr(0,10)),\n 'ends': value.ends === undefined ? undefined : (value.ends.toISOString().substr(0,10)),\n 'registrationbegins': value.registrationbegins === undefined ? undefined : (value.registrationbegins.toISOString()),\n 'registrationendssoft': value.registrationendssoft === undefined ? undefined : (value.registrationendssoft.toISOString()),\n 'registrationendshard': value.registrationendshard === undefined ? undefined : (value.registrationendshard.toISOString()),\n 'registrationopen': value.registrationopen,\n 'teacher': value.teacher,\n 'ectscredits': value.ectscredits,\n 'topical': value.topical,\n 'days': value.days === undefined ? undefined : ((value.days as Array).map(HellewiCourseDayToJSON)),\n 'location': HellewiLocationToJSON(value.location),\n 'notifications': value.notifications === undefined ? undefined : ((value.notifications as Array).map(HellewiCourseNotificationToJSON)),\n 'periods': value.periods === undefined ? undefined : ((value.periods as Array).map(HellewiCoursePeriodToJSON)),\n 'language': HellewiLanguageToJSON(value.language),\n 'tags': value.tags === undefined ? undefined : ((value.tags as Array).map(HellewiTagToJSON)),\n 'prices': value.prices === undefined ? undefined : ((value.prices as Array).map(HellewiCoursePriceToJSON)),\n 'moduleparent': HellewiCoursePartialToJSON(value.moduleparent),\n 'modulechildren': value.modulechildren === undefined ? undefined : ((value.modulechildren as Array).map(HellewiCoursePartialToJSON)),\n 'catalogitems': ((value.catalogitems as Array).map(HellewiCatalogItemToJSON)),\n 'department': HellewiCatalogItemToJSON(value.department),\n 'category': HellewiCatalogItemToJSON(value.category),\n 'subject': HellewiCatalogItemToJSON(value.subject),\n 'description': value.description,\n 'keywords': value.keywords,\n 'lessons': value.lessons === undefined ? undefined : ((value.lessons as Array).map(HellewiCourseLessonToJSON)),\n 'participantcount': HellewiParticipantCountToJSON(value.participantcount),\n 'registrationlink': value.registrationlink,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface HellewiCourseCount\n */\nexport interface HellewiCourseCount {\n [key: string]: object | any;\n /**\n * Course count\n * @type {number}\n * @memberof HellewiCourseCount\n */\n count: number;\n}\n\nexport function HellewiCourseCountFromJSON(json: any): HellewiCourseCount {\n return HellewiCourseCountFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseCountFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourseCount {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'count': json['count'],\n };\n}\n\nexport function HellewiCourseCountToJSON(value?: HellewiCourseCount | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'count': value.count,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n Weekday,\n WeekdayFromJSON,\n WeekdayFromJSONTyped,\n WeekdayToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCourseDay\n */\nexport interface HellewiCourseDay {\n [key: string]: object | any;\n /**\n * \n * @type {Weekday}\n * @memberof HellewiCourseDay\n */\n weekday?: Weekday;\n /**\n * Time when course begins on this day, as \\\"HH:MM\\\"\n * @type {string}\n * @memberof HellewiCourseDay\n */\n begins?: string;\n /**\n * Time when course ends on this day, as \\\"HH:MM\\\"\n * @type {string}\n * @memberof HellewiCourseDay\n */\n ends?: string;\n /**\n * Keywords that can be used to match filters\n * @type {Array}\n * @memberof HellewiCourseDay\n */\n keywords?: Array;\n}\n\nexport function HellewiCourseDayFromJSON(json: any): HellewiCourseDay {\n return HellewiCourseDayFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseDayFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourseDay {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'weekday': !exists(json, 'weekday') ? undefined : WeekdayFromJSON(json['weekday']),\n 'begins': !exists(json, 'begins') ? undefined : json['begins'],\n 'ends': !exists(json, 'ends') ? undefined : json['ends'],\n 'keywords': !exists(json, 'keywords') ? undefined : json['keywords'],\n };\n}\n\nexport function HellewiCourseDayToJSON(value?: HellewiCourseDay | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'weekday': WeekdayToJSON(value.weekday),\n 'begins': value.begins,\n 'ends': value.ends,\n 'keywords': value.keywords,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCoursePrice,\n HellewiCoursePriceFromJSON,\n HellewiCoursePriceFromJSONTyped,\n HellewiCoursePriceToJSON,\n HellewiLocation,\n HellewiLocationFromJSON,\n HellewiLocationFromJSONTyped,\n HellewiLocationToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCourseLesson\n */\nexport interface HellewiCourseLesson {\n [key: string]: object | any;\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 * Whether you can register to this lesson\n * @type {boolean}\n * @memberof HellewiCourseLesson\n */\n registrationopen?: boolean;\n /**\n * \n * @type {HellewiCoursePrice}\n * @memberof HellewiCourseLesson\n */\n price?: HellewiCoursePrice;\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 === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'begins': !exists(json, 'begins') ? undefined : (new Date(json['begins'])),\n 'ends': !exists(json, 'ends') ? undefined : (new Date(json['ends'])),\n 'location': !exists(json, 'location') ? undefined : HellewiLocationFromJSON(json['location']),\n 'registrationopen': !exists(json, 'registrationopen') ? undefined : json['registrationopen'],\n 'price': !exists(json, 'price') ? undefined : HellewiCoursePriceFromJSON(json['price']),\n };\n}\n\nexport function HellewiCourseLessonToJSON(value?: HellewiCourseLesson | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'begins': value.begins === undefined ? undefined : (value.begins.toISOString()),\n 'ends': value.ends === undefined ? undefined : (value.ends.toISOString()),\n 'location': HellewiLocationToJSON(value.location),\n 'registrationopen': value.registrationopen,\n 'price': HellewiCoursePriceToJSON(value.price),\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface HellewiCourseMinimal\n */\nexport interface HellewiCourseMinimal {\n [key: string]: object | any;\n /**\n * Course ID This is either - a number as string (single-tenant endpoints, e.g. `\\'3\\'`) - string with tenant id (in lowercase) and course id number (multi-tenant endpoints, e.g. `\\'demo.opistopalvelut.fi-3\\'`) Validation pattern: `^(?:[a-z0-9-.]+-)?[0-9]+$`\n * @type {string}\n * @memberof HellewiCourseMinimal\n */\n id: string;\n /**\n * Code / koodi\n * @type {string}\n * @memberof HellewiCourseMinimal\n */\n code?: string;\n /**\n * Name\n * @type {string}\n * @memberof HellewiCourseMinimal\n */\n name?: string;\n /**\n * Tenant\n * @type {string}\n * @memberof HellewiCourseMinimal\n */\n tenant: string;\n}\n\nexport function HellewiCourseMinimalFromJSON(json: any): HellewiCourseMinimal {\n return HellewiCourseMinimalFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseMinimalFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourseMinimal {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'id': json['id'],\n 'code': !exists(json, 'code') ? undefined : json['code'],\n 'name': !exists(json, 'name') ? undefined : json['name'],\n 'tenant': json['tenant'],\n };\n}\n\nexport function HellewiCourseMinimalToJSON(value?: HellewiCourseMinimal | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'id': value.id,\n 'code': value.code,\n 'name': value.name,\n 'tenant': value.tenant,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface HellewiCourseMinimalParent\n */\nexport interface HellewiCourseMinimalParent {\n [key: string]: object | any;\n /**\n * Course ID This is either - a number as string (single-tenant endpoints, e.g. `\\'3\\'`) - string with tenant id (in lowercase) and course id number (multi-tenant endpoints, e.g. `\\'demo.opistopalvelut.fi-3\\'`) Validation pattern: `^(?:[a-z0-9-.]+-)?[0-9]+$`\n * @type {string}\n * @memberof HellewiCourseMinimalParent\n */\n id: string;\n /**\n * Code / koodi\n * @type {string}\n * @memberof HellewiCourseMinimalParent\n */\n code?: string;\n /**\n * Name\n * @type {string}\n * @memberof HellewiCourseMinimalParent\n */\n name?: string;\n /**\n * Tenant\n * @type {string}\n * @memberof HellewiCourseMinimalParent\n */\n tenant: string;\n /**\n * Keywords that can be used to match filters\n * @type {Array}\n * @memberof HellewiCourseMinimalParent\n */\n keywords?: Array;\n}\n\nexport function HellewiCourseMinimalParentFromJSON(json: any): HellewiCourseMinimalParent {\n return HellewiCourseMinimalParentFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseMinimalParentFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourseMinimalParent {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'id': json['id'],\n 'code': !exists(json, 'code') ? undefined : json['code'],\n 'name': !exists(json, 'name') ? undefined : json['name'],\n 'tenant': json['tenant'],\n 'keywords': !exists(json, 'keywords') ? undefined : json['keywords'],\n };\n}\n\nexport function HellewiCourseMinimalParentToJSON(value?: HellewiCourseMinimalParent | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'id': value.id,\n 'code': value.code,\n 'name': value.name,\n 'tenant': value.tenant,\n 'keywords': value.keywords,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCourseNotificationLabel,\n HellewiCourseNotificationLabelFromJSON,\n HellewiCourseNotificationLabelFromJSONTyped,\n HellewiCourseNotificationLabelToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCourseNotification\n */\nexport interface HellewiCourseNotification {\n [key: string]: object | any;\n /**\n * \n * @type {HellewiCourseNotificationLabel}\n * @memberof HellewiCourseNotification\n */\n label: HellewiCourseNotificationLabel;\n /**\n * Text\n * @type {string}\n * @memberof HellewiCourseNotification\n */\n text: string;\n}\n\nexport function HellewiCourseNotificationFromJSON(json: any): HellewiCourseNotification {\n return HellewiCourseNotificationFromJSONTyped(json, false);\n}\n\nexport function HellewiCourseNotificationFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCourseNotification {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'label': HellewiCourseNotificationLabelFromJSON(json['label']),\n 'text': json['text'],\n };\n}\n\nexport function HellewiCourseNotificationToJSON(value?: HellewiCourseNotification | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'label': HellewiCourseNotificationLabelToJSON(value.label),\n 'text': value.text,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCatalogItem,\n HellewiCatalogItemFromJSON,\n HellewiCatalogItemFromJSONTyped,\n HellewiCatalogItemToJSON,\n HellewiCourseDay,\n HellewiCourseDayFromJSON,\n HellewiCourseDayFromJSONTyped,\n HellewiCourseDayToJSON,\n HellewiCourseMinimal,\n HellewiCourseMinimalFromJSON,\n HellewiCourseMinimalFromJSONTyped,\n HellewiCourseMinimalToJSON,\n HellewiCourseMinimalParent,\n HellewiCourseMinimalParentFromJSON,\n HellewiCourseMinimalParentFromJSONTyped,\n HellewiCourseMinimalParentToJSON,\n HellewiCourseNotification,\n HellewiCourseNotificationFromJSON,\n HellewiCourseNotificationFromJSONTyped,\n HellewiCourseNotificationToJSON,\n HellewiCoursePeriod,\n HellewiCoursePeriodFromJSON,\n HellewiCoursePeriodFromJSONTyped,\n HellewiCoursePeriodToJSON,\n HellewiCoursePrice,\n HellewiCoursePriceFromJSON,\n HellewiCoursePriceFromJSONTyped,\n HellewiCoursePriceToJSON,\n HellewiCourseStatus,\n HellewiCourseStatusFromJSON,\n HellewiCourseStatusFromJSONTyped,\n HellewiCourseStatusToJSON,\n HellewiLanguage,\n HellewiLanguageFromJSON,\n HellewiLanguageFromJSONTyped,\n HellewiLanguageToJSON,\n HellewiLocation,\n HellewiLocationFromJSON,\n HellewiLocationFromJSONTyped,\n HellewiLocationToJSON,\n HellewiTag,\n HellewiTagFromJSON,\n HellewiTagFromJSONTyped,\n HellewiTagToJSON,\n} from './';\n\n/**\n * Course with limited fields\n * @export\n * @interface HellewiCoursePartial\n */\nexport interface HellewiCoursePartial {\n [key: string]: object | any;\n /**\n * Course ID This is either - a number as string (single-tenant endpoints, e.g. `\\'3\\'`) - string with tenant id (in lowercase) and course id number (multi-tenant endpoints, e.g. `\\'demo.opistopalvelut.fi-3\\'`) Validation pattern: `^(?:[a-z0-9-.]+-)?[0-9]+$`\n * @type {string}\n * @memberof HellewiCoursePartial\n */\n id: string;\n /**\n * Code / koodi\n * @type {string}\n * @memberof HellewiCoursePartial\n */\n code?: string;\n /**\n * Name\n * @type {string}\n * @memberof HellewiCoursePartial\n */\n name?: string;\n /**\n * Tenant\n * @type {string}\n * @memberof HellewiCoursePartial\n */\n tenant: string;\n /**\n * Course statuses - `NOT_YET_STARTED` Course has not yet started - `IN_PROGRESS` Course is in progress - `ENDED` Course has ended - `CANCELLED` Course has been cancelled (before it started) - `INTERRUPTED` Course has been interrupted (after it started) Currently only one of the statuses can be active at the same time, but it is also possible that none of them are. Statuses can be added in the future, so the field is an array, and implementation cannot make any assumptions that the requested status would be always in index 0.\n * @type {Array}\n * @memberof HellewiCoursePartial\n */\n statuses: Array;\n /**\n * Course begins on date\n * @type {Date}\n * @memberof HellewiCoursePartial\n */\n begins?: Date;\n /**\n * Course ends on date\n * @type {Date}\n * @memberof HellewiCoursePartial\n */\n ends?: Date;\n /**\n * Registration begins on date/time null means that registration is not open\n * @type {Date}\n * @memberof HellewiCoursePartial\n */\n registrationbegins?: Date;\n /**\n * Registration ends on date/time, soft limit If this time is in the past, registrations are still accepted, but user interfaces should show this field as time when registrations close\n * @type {Date}\n * @memberof HellewiCoursePartial\n */\n registrationendssoft?: Date;\n /**\n * Registration ends on date/time, hard limit null means that registration has no ending limit\n * @type {Date}\n * @memberof HellewiCoursePartial\n */\n registrationendshard?: Date;\n /**\n * Whether registration is open at the moment See rules in [Registration](#section/Registration)\n * @type {boolean}\n * @memberof HellewiCoursePartial\n */\n registrationopen?: boolean;\n /**\n * Teacher\n * @type {string}\n * @memberof HellewiCoursePartial\n */\n teacher?: string;\n /**\n * ECTS credits / opintopisteet\n * @type {number}\n * @memberof HellewiCoursePartial\n */\n ectscredits?: number;\n /**\n * Topical / ajankohtainen This course should be emphasized\n * @type {boolean}\n * @memberof HellewiCoursePartial\n */\n topical?: boolean;\n /**\n * Day(s) / kurssipäivät\n * @type {Array}\n * @memberof HellewiCoursePartial\n */\n days?: Array;\n /**\n * \n * @type {HellewiLocation}\n * @memberof HellewiCoursePartial\n */\n location?: HellewiLocation;\n /**\n * Notification\n * @type {Array}\n * @memberof HellewiCoursePartial\n */\n notifications?: Array;\n /**\n * Periods and terms / lukukaudet ja lukuvuodet\n * @type {Array}\n * @memberof HellewiCoursePartial\n */\n periods?: Array;\n /**\n * \n * @type {HellewiLanguage}\n * @memberof HellewiCoursePartial\n */\n language?: HellewiLanguage;\n /**\n * Tags\n * @type {Array}\n * @memberof HellewiCoursePartial\n */\n tags?: Array;\n /**\n * Prices\n * @type {Array}\n * @memberof HellewiCoursePartial\n */\n prices?: Array;\n /**\n * \n * @type {HellewiCourseMinimalParent}\n * @memberof HellewiCoursePartial\n */\n moduleparent?: HellewiCourseMinimalParent;\n /**\n * Child courses for a module parent course\n * @type {Array}\n * @memberof HellewiCoursePartial\n */\n modulechildren?: Array;\n /**\n * Catalog items Different item types are explained under [GetCatalog](#operation/GetCatalog) response\n * @type {Array}\n * @memberof HellewiCoursePartial\n */\n catalogitems: Array;\n}\n\nexport function HellewiCoursePartialFromJSON(json: any): HellewiCoursePartial {\n return HellewiCoursePartialFromJSONTyped(json, false);\n}\n\nexport function HellewiCoursePartialFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCoursePartial {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'id': json['id'],\n 'code': !exists(json, 'code') ? undefined : json['code'],\n 'name': !exists(json, 'name') ? undefined : json['name'],\n 'tenant': json['tenant'],\n 'statuses': ((json['statuses'] as Array).map(HellewiCourseStatusFromJSON)),\n 'begins': !exists(json, 'begins') ? undefined : (new Date(json['begins'])),\n 'ends': !exists(json, 'ends') ? undefined : (new Date(json['ends'])),\n 'registrationbegins': !exists(json, 'registrationbegins') ? undefined : (new Date(json['registrationbegins'])),\n 'registrationendssoft': !exists(json, 'registrationendssoft') ? undefined : (new Date(json['registrationendssoft'])),\n 'registrationendshard': !exists(json, 'registrationendshard') ? undefined : (new Date(json['registrationendshard'])),\n 'registrationopen': !exists(json, 'registrationopen') ? undefined : json['registrationopen'],\n 'teacher': !exists(json, 'teacher') ? undefined : json['teacher'],\n 'ectscredits': !exists(json, 'ectscredits') ? undefined : json['ectscredits'],\n 'topical': !exists(json, 'topical') ? undefined : json['topical'],\n 'days': !exists(json, 'days') ? undefined : ((json['days'] as Array).map(HellewiCourseDayFromJSON)),\n 'location': !exists(json, 'location') ? undefined : HellewiLocationFromJSON(json['location']),\n 'notifications': !exists(json, 'notifications') ? undefined : ((json['notifications'] as Array).map(HellewiCourseNotificationFromJSON)),\n 'periods': !exists(json, 'periods') ? undefined : ((json['periods'] as Array).map(HellewiCoursePeriodFromJSON)),\n 'language': !exists(json, 'language') ? undefined : HellewiLanguageFromJSON(json['language']),\n 'tags': !exists(json, 'tags') ? undefined : ((json['tags'] as Array).map(HellewiTagFromJSON)),\n 'prices': !exists(json, 'prices') ? undefined : ((json['prices'] as Array).map(HellewiCoursePriceFromJSON)),\n 'moduleparent': !exists(json, 'moduleparent') ? undefined : HellewiCourseMinimalParentFromJSON(json['moduleparent']),\n 'modulechildren': !exists(json, 'modulechildren') ? undefined : ((json['modulechildren'] as Array).map(HellewiCourseMinimalFromJSON)),\n 'catalogitems': ((json['catalogitems'] as Array).map(HellewiCatalogItemFromJSON)),\n };\n}\n\nexport function HellewiCoursePartialToJSON(value?: HellewiCoursePartial | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'id': value.id,\n 'code': value.code,\n 'name': value.name,\n 'tenant': value.tenant,\n 'statuses': ((value.statuses as Array).map(HellewiCourseStatusToJSON)),\n 'begins': value.begins === undefined ? undefined : (value.begins.toISOString().substr(0,10)),\n 'ends': value.ends === undefined ? undefined : (value.ends.toISOString().substr(0,10)),\n 'registrationbegins': value.registrationbegins === undefined ? undefined : (value.registrationbegins.toISOString()),\n 'registrationendssoft': value.registrationendssoft === undefined ? undefined : (value.registrationendssoft.toISOString()),\n 'registrationendshard': value.registrationendshard === undefined ? undefined : (value.registrationendshard.toISOString()),\n 'registrationopen': value.registrationopen,\n 'teacher': value.teacher,\n 'ectscredits': value.ectscredits,\n 'topical': value.topical,\n 'days': value.days === undefined ? undefined : ((value.days as Array).map(HellewiCourseDayToJSON)),\n 'location': HellewiLocationToJSON(value.location),\n 'notifications': value.notifications === undefined ? undefined : ((value.notifications as Array).map(HellewiCourseNotificationToJSON)),\n 'periods': value.periods === undefined ? undefined : ((value.periods as Array).map(HellewiCoursePeriodToJSON)),\n 'language': HellewiLanguageToJSON(value.language),\n 'tags': value.tags === undefined ? undefined : ((value.tags as Array).map(HellewiTagToJSON)),\n 'prices': value.prices === undefined ? undefined : ((value.prices as Array).map(HellewiCoursePriceToJSON)),\n 'moduleparent': HellewiCourseMinimalParentToJSON(value.moduleparent),\n 'modulechildren': value.modulechildren === undefined ? undefined : ((value.modulechildren as Array).map(HellewiCourseMinimalToJSON)),\n 'catalogitems': ((value.catalogitems as Array).map(HellewiCatalogItemToJSON)),\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCourseLesson,\n HellewiCourseLessonFromJSON,\n HellewiCourseLessonFromJSONTyped,\n HellewiCourseLessonToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCoursePeriod\n */\nexport interface HellewiCoursePeriod {\n [key: string]: object | any;\n /**\n * Course period begins on date\n * @type {Date}\n * @memberof HellewiCoursePeriod\n */\n begins?: Date;\n /**\n * Course period ends on date\n * @type {Date}\n * @memberof HellewiCoursePeriod\n */\n ends?: Date;\n /**\n * Lesson count / kertoja\n * @type {number}\n * @memberof HellewiCoursePeriod\n */\n lessoncount?: number;\n /**\n * Lessons This is only present in [GetCourse](#operation/GetCourse) endpoint (not in ListCourses)\n * @type {Array}\n * @memberof HellewiCoursePeriod\n */\n lessons?: Array;\n /**\n * Name\n * @type {string}\n * @memberof HellewiCoursePeriod\n */\n name: string;\n /**\n * Keywords that can be used to match filters\n * @type {Array}\n * @memberof HellewiCoursePeriod\n */\n keywords?: Array;\n}\n\nexport function HellewiCoursePeriodFromJSON(json: any): HellewiCoursePeriod {\n return HellewiCoursePeriodFromJSONTyped(json, false);\n}\n\nexport function HellewiCoursePeriodFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCoursePeriod {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'begins': !exists(json, 'begins') ? undefined : (new Date(json['begins'])),\n 'ends': !exists(json, 'ends') ? undefined : (new Date(json['ends'])),\n 'lessoncount': !exists(json, 'lessoncount') ? undefined : json['lessoncount'],\n 'lessons': !exists(json, 'lessons') ? undefined : ((json['lessons'] as Array).map(HellewiCourseLessonFromJSON)),\n 'name': json['name'],\n 'keywords': !exists(json, 'keywords') ? undefined : json['keywords'],\n };\n}\n\nexport function HellewiCoursePeriodToJSON(value?: HellewiCoursePeriod | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'begins': value.begins === undefined ? undefined : (value.begins.toISOString().substr(0,10)),\n 'ends': value.ends === undefined ? undefined : (value.ends.toISOString().substr(0,10)),\n 'lessoncount': value.lessoncount,\n 'lessons': value.lessons === undefined ? undefined : ((value.lessons as Array).map(HellewiCourseLessonToJSON)),\n 'name': value.name,\n 'keywords': value.keywords,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCoursePriceInstallment,\n HellewiCoursePriceInstallmentFromJSON,\n HellewiCoursePriceInstallmentFromJSONTyped,\n HellewiCoursePriceInstallmentToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCoursePrice\n */\nexport interface HellewiCoursePrice {\n [key: string]: object | any;\n /**\n * Whether this price is the default one There is only one price with default=true per course\n * @type {boolean}\n * @memberof HellewiCoursePrice\n */\n _default?: boolean;\n /**\n * Price category name\n * @type {string}\n * @memberof HellewiCoursePrice\n */\n name?: string;\n /**\n * Price amount in euro cents\n * @type {number}\n * @memberof HellewiCoursePrice\n */\n amount?: number;\n /**\n * Payment can be done now\n * @type {boolean}\n * @memberof HellewiCoursePrice\n */\n paymentnow: boolean;\n /**\n * Payment can be done later\n * @type {boolean}\n * @memberof HellewiCoursePrice\n */\n paymentlater: boolean;\n /**\n * Payment with culture voucher This field is present only if culture vouchers are enabled as payment options\n * @type {boolean}\n * @memberof HellewiCoursePrice\n */\n paymentwithculturevoucher?: boolean;\n /**\n * Payment with sports voucher This field is present only if sports vouchers are enabled as payment options\n * @type {boolean}\n * @memberof HellewiCoursePrice\n */\n paymentwithsportsvoucher?: boolean;\n /**\n * Installment groups Normal course prices can be configured to be paid via installments, lessons cannot.\n * @type {Array}\n * @memberof HellewiCoursePrice\n */\n installmentgroups?: Array;\n}\n\nexport function HellewiCoursePriceFromJSON(json: any): HellewiCoursePrice {\n return HellewiCoursePriceFromJSONTyped(json, false);\n}\n\nexport function HellewiCoursePriceFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCoursePrice {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n '_default': !exists(json, 'default') ? undefined : json['default'],\n 'name': !exists(json, 'name') ? undefined : json['name'],\n 'amount': !exists(json, 'amount') ? undefined : json['amount'],\n 'paymentnow': json['paymentnow'],\n 'paymentlater': json['paymentlater'],\n 'paymentwithculturevoucher': !exists(json, 'paymentwithculturevoucher') ? undefined : json['paymentwithculturevoucher'],\n 'paymentwithsportsvoucher': !exists(json, 'paymentwithsportsvoucher') ? undefined : json['paymentwithsportsvoucher'],\n 'installmentgroups': !exists(json, 'installmentgroups') ? undefined : ((json['installmentgroups'] as Array).map(HellewiCoursePriceInstallmentFromJSON)),\n };\n}\n\nexport function HellewiCoursePriceToJSON(value?: HellewiCoursePrice | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'default': value._default,\n 'name': value.name,\n 'amount': value.amount,\n 'paymentnow': value.paymentnow,\n 'paymentlater': value.paymentlater,\n 'paymentwithculturevoucher': value.paymentwithculturevoucher,\n 'paymentwithsportsvoucher': value.paymentwithsportsvoucher,\n 'installmentgroups': value.installmentgroups === undefined ? undefined : ((value.installmentgroups as Array).map(HellewiCoursePriceInstallmentToJSON)),\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiCoursePriceInstallmentInstallments,\n HellewiCoursePriceInstallmentInstallmentsFromJSON,\n HellewiCoursePriceInstallmentInstallmentsFromJSONTyped,\n HellewiCoursePriceInstallmentInstallmentsToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiCoursePriceInstallment\n */\nexport interface HellewiCoursePriceInstallment {\n [key: string]: object | any;\n /**\n * Installment group name\n * @type {string}\n * @memberof HellewiCoursePriceInstallment\n */\n name: string;\n /**\n * \n * @type {Array}\n * @memberof HellewiCoursePriceInstallment\n */\n installments: Array;\n}\n\nexport function HellewiCoursePriceInstallmentFromJSON(json: any): HellewiCoursePriceInstallment {\n return HellewiCoursePriceInstallmentFromJSONTyped(json, false);\n}\n\nexport function HellewiCoursePriceInstallmentFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCoursePriceInstallment {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'name': json['name'],\n 'installments': ((json['installments'] as Array).map(HellewiCoursePriceInstallmentInstallmentsFromJSON)),\n };\n}\n\nexport function HellewiCoursePriceInstallmentToJSON(value?: HellewiCoursePriceInstallment | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'name': value.name,\n 'installments': ((value.installments as Array).map(HellewiCoursePriceInstallmentInstallmentsToJSON)),\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface HellewiCoursePriceInstallmentInstallments\n */\nexport interface HellewiCoursePriceInstallmentInstallments {\n /**\n * Payment can be done later\n * @type {boolean}\n * @memberof HellewiCoursePriceInstallmentInstallments\n */\n paymentlater: boolean;\n /**\n * Payment can be done now\n * @type {boolean}\n * @memberof HellewiCoursePriceInstallmentInstallments\n */\n paymentnow: boolean;\n /**\n * Price amount in euro cents\n * @type {number}\n * @memberof HellewiCoursePriceInstallmentInstallments\n */\n amount: number;\n /**\n * Installment name\n * @type {string}\n * @memberof HellewiCoursePriceInstallmentInstallments\n */\n name?: string;\n}\n\nexport function HellewiCoursePriceInstallmentInstallmentsFromJSON(json: any): HellewiCoursePriceInstallmentInstallments {\n return HellewiCoursePriceInstallmentInstallmentsFromJSONTyped(json, false);\n}\n\nexport function HellewiCoursePriceInstallmentInstallmentsFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiCoursePriceInstallmentInstallments {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n 'paymentlater': json['paymentlater'],\n 'paymentnow': json['paymentnow'],\n 'amount': json['amount'],\n 'name': !exists(json, 'name') ? undefined : json['name'],\n };\n}\n\nexport function HellewiCoursePriceInstallmentInstallmentsToJSON(value?: HellewiCoursePriceInstallmentInstallments | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n 'paymentlater': value.paymentlater,\n 'paymentnow': value.paymentnow,\n 'amount': value.amount,\n 'name': value.name,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface HellewiLanguage\n */\nexport interface HellewiLanguage {\n [key: string]: object | any;\n /**\n * Name\n * @type {string}\n * @memberof HellewiLanguage\n */\n name: string;\n /**\n * Keywords that can be used to match filters\n * @type {Array}\n * @memberof HellewiLanguage\n */\n keywords?: Array;\n}\n\nexport function HellewiLanguageFromJSON(json: any): HellewiLanguage {\n return HellewiLanguageFromJSONTyped(json, false);\n}\n\nexport function HellewiLanguageFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiLanguage {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'name': json['name'],\n 'keywords': !exists(json, 'keywords') ? undefined : json['keywords'],\n };\n}\n\nexport function HellewiLanguageToJSON(value?: HellewiLanguage | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'name': value.name,\n 'keywords': value.keywords,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n Geopoint,\n GeopointFromJSON,\n GeopointFromJSONTyped,\n GeopointToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiLocation\n */\nexport interface HellewiLocation {\n [key: string]: object | 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 This is in always included [/locations](#tag/Location) response 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\nexport function HellewiLocationFromJSON(json: any): HellewiLocation {\n return HellewiLocationFromJSONTyped(json, false);\n}\n\nexport function HellewiLocationFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiLocation {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'address': !exists(json, 'address') ? undefined : json['address'],\n 'city': !exists(json, 'city') ? undefined : json['city'],\n 'id': !exists(json, 'id') ? undefined : json['id'],\n 'latlon': !exists(json, 'latlon') ? undefined : GeopointFromJSON(json['latlon']),\n 'name': json['name'],\n 'postalcode': !exists(json, 'postalcode') ? undefined : json['postalcode'],\n 'keywords': !exists(json, 'keywords') ? undefined : json['keywords'],\n };\n}\n\nexport function HellewiLocationToJSON(value?: HellewiLocation | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\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 };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * Participant count in a single course Optional fields will always be there if global parameter registrationsettings.showseatcount is set to true, or if course parameter showplacecount is set to true\n * @export\n * @interface HellewiParticipantCount\n */\nexport interface HellewiParticipantCount {\n [key: string]: object | any;\n /**\n * Course id\n * @type {string}\n * @memberof HellewiParticipantCount\n */\n id: string;\n /**\n * Course is almost full: less than 10% of places available\n * @type {boolean}\n * @memberof HellewiParticipantCount\n */\n almostfull: boolean;\n /**\n * Course is full You might still be able to register for queueing\n * @type {boolean}\n * @memberof HellewiParticipantCount\n */\n full: boolean;\n /**\n * Maximum number of participants\n * @type {number}\n * @memberof HellewiParticipantCount\n */\n max?: number;\n /**\n * Spares are full\n * @type {boolean}\n * @memberof HellewiParticipantCount\n */\n sparefull: boolean;\n /**\n * Available places for registration\n * @type {number}\n * @memberof HellewiParticipantCount\n */\n available?: number;\n /**\n * How many times course can be added to cart\n * @type {number}\n * @memberof HellewiParticipantCount\n */\n cartlimit: number;\n /**\n * Minimum number of participants\n * @type {number}\n * @memberof HellewiParticipantCount\n */\n min?: number;\n /**\n * Actual registrations\n * @type {number}\n * @memberof HellewiParticipantCount\n */\n registrations?: number;\n /**\n * Registration is open\n * @type {boolean}\n * @memberof HellewiParticipantCount\n */\n registrationopen: boolean;\n /**\n * Participants queuing for available places\n * @type {number}\n * @memberof HellewiParticipantCount\n */\n spare?: number;\n /**\n * Number of places available in queue\n * @type {number}\n * @memberof HellewiParticipantCount\n */\n spareavailable?: number;\n /**\n * Maximum number of participants in queue\n * @type {number}\n * @memberof HellewiParticipantCount\n */\n sparemax?: number;\n}\n\nexport function HellewiParticipantCountFromJSON(json: any): HellewiParticipantCount {\n return HellewiParticipantCountFromJSONTyped(json, false);\n}\n\nexport function HellewiParticipantCountFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiParticipantCount {\n if ((json === undefined) || (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': !exists(json, 'max') ? undefined : json['max'],\n 'sparefull': json['sparefull'],\n 'available': !exists(json, 'available') ? undefined : json['available'],\n 'cartlimit': json['cartlimit'],\n 'min': !exists(json, 'min') ? undefined : json['min'],\n 'registrations': !exists(json, 'registrations') ? undefined : json['registrations'],\n 'registrationopen': json['registrationopen'],\n 'spare': !exists(json, 'spare') ? undefined : json['spare'],\n 'spareavailable': !exists(json, 'spareavailable') ? undefined : json['spareavailable'],\n 'sparemax': !exists(json, 'sparemax') ? undefined : json['sparemax'],\n };\n}\n\nexport function HellewiParticipantCountToJSON(value?: HellewiParticipantCount | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'id': value.id,\n 'almostfull': value.almostfull,\n 'full': value.full,\n 'max': value.max,\n 'sparefull': value.sparefull,\n 'available': value.available,\n 'cartlimit': value.cartlimit,\n 'min': value.min,\n 'registrations': value.registrations,\n 'registrationopen': value.registrationopen,\n 'spare': value.spare,\n 'spareavailable': value.spareavailable,\n 'sparemax': value.sparemax,\n };\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` - `:<` 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 ### 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 \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 * @export\n * @enum {string}\n */\nexport enum PurchaseProductItemType {\n Course = 'course',\n Lesson = 'lesson',\n Installment = 'installment',\n Discount = 'discount',\n Universitypriceshare = 'universitypriceshare'\n}\n\nexport function PurchaseProductItemTypeFromJSON(json: any): PurchaseProductItemType {\n return PurchaseProductItemTypeFromJSONTyped(json, false);\n}\n\nexport function PurchaseProductItemTypeFromJSONTyped(json: any, ignoreDiscriminator: boolean): PurchaseProductItemType {\n return json as PurchaseProductItemType;\n}\n\nexport function PurchaseProductItemTypeToJSON(value?: PurchaseProductItemType | 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` - `:<` 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 ### 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 \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 * @export\n * @enum {string}\n */\nexport enum PurchaseProductType {\n Course = 'course',\n Discount = 'discount'\n}\n\nexport function PurchaseProductTypeFromJSON(json: any): PurchaseProductType {\n return PurchaseProductTypeFromJSONTyped(json, false);\n}\n\nexport function PurchaseProductTypeFromJSONTyped(json: any, ignoreDiscriminator: boolean): PurchaseProductType {\n return json as PurchaseProductType;\n}\n\nexport function PurchaseProductTypeToJSON(value?: PurchaseProductType | 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` - `:<` 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 ### 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 \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 * Weekday as a number, 1 = Monday, 7 = Sunday\n * @export\n * @enum {string}\n */\nexport enum Weekday {\n NUMBER_1 = 1,\n NUMBER_2 = 2,\n NUMBER_3 = 3,\n NUMBER_4 = 4,\n NUMBER_5 = 5,\n NUMBER_6 = 6,\n NUMBER_7 = 7\n}\n\nexport function WeekdayFromJSON(json: any): Weekday {\n return WeekdayFromJSONTyped(json, false);\n}\n\nexport function WeekdayFromJSONTyped(json: any, ignoreDiscriminator: boolean): Weekday {\n return json as Weekday;\n}\n\nexport function WeekdayToJSON(value?: Weekday | 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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\n/**\n * \n * @export\n * @interface HellewiTag\n */\nexport interface HellewiTag {\n [key: string]: object | any;\n /**\n * Name\n * @type {string}\n * @memberof HellewiTag\n */\n name: string;\n /**\n * Description\n * @type {string}\n * @memberof HellewiTag\n */\n description?: string;\n /**\n * Background color\n * @type {string}\n * @memberof HellewiTag\n */\n color?: string;\n /**\n * Font color\n * @type {string}\n * @memberof HellewiTag\n */\n fontcolor?: string;\n /**\n * Keywords that can be used to match filters\n * @type {Array}\n * @memberof HellewiTag\n */\n keywords?: Array;\n}\n\nexport function HellewiTagFromJSON(json: any): HellewiTag {\n return HellewiTagFromJSONTyped(json, false);\n}\n\nexport function HellewiTagFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiTag {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'name': json['name'],\n 'description': !exists(json, 'description') ? undefined : json['description'],\n 'color': !exists(json, 'color') ? undefined : json['color'],\n 'fontcolor': !exists(json, 'fontcolor') ? undefined : json['fontcolor'],\n 'keywords': !exists(json, 'keywords') ? undefined : json['keywords'],\n };\n}\n\nexport function HellewiTagToJSON(value?: HellewiTag | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'name': value.name,\n 'description': value.description,\n 'color': value.color,\n 'fontcolor': value.fontcolor,\n 'keywords': value.keywords,\n };\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` - `:<` 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 ### 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 \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 { exists, mapValues } from '../runtime';\nimport {\n HellewiLocation,\n HellewiLocationFromJSON,\n HellewiLocationFromJSONTyped,\n HellewiLocationToJSON,\n} from './';\n\n/**\n * \n * @export\n * @interface HellewiTenant\n */\nexport interface HellewiTenant {\n [key: string]: object | any;\n /**\n * Tenant identifier\n * @type {string}\n * @memberof HellewiTenant\n */\n tenant: string;\n /**\n * Tenant\\'s name\n * @type {string}\n * @memberof HellewiTenant\n */\n name: string;\n /**\n * URL for tenant\\'s logo\n * @type {string}\n * @memberof HellewiTenant\n */\n logo?: string;\n /**\n * URL to tenant\\'s homepage\n * @type {string}\n * @memberof HellewiTenant\n */\n homepage?: string;\n /**\n * URL to tenant\\'s Twitter account\n * @type {string}\n * @memberof HellewiTenant\n */\n twitter?: string;\n /**\n * URL to tenant\\'s Facebook account\n * @type {string}\n * @memberof HellewiTenant\n */\n facebook?: string;\n /**\n * URL to tenant\\'s Instagram account\n * @type {string}\n * @memberof HellewiTenant\n */\n instagram?: string;\n /**\n * URL to tenant\\'s LinkedIn account\n * @type {string}\n * @memberof HellewiTenant\n */\n linkedin?: string;\n /**\n * \n * @type {HellewiLocation}\n * @memberof HellewiTenant\n */\n location?: HellewiLocation;\n /**\n * Tenant\\'s customer service phone number\n * @type {string}\n * @memberof HellewiTenant\n */\n phone?: string;\n /**\n * Tenant\\'s customer service email address\n * @type {string}\n * @memberof HellewiTenant\n */\n email?: string;\n}\n\nexport function HellewiTenantFromJSON(json: any): HellewiTenant {\n return HellewiTenantFromJSONTyped(json, false);\n}\n\nexport function HellewiTenantFromJSONTyped(json: any, ignoreDiscriminator: boolean): HellewiTenant {\n if ((json === undefined) || (json === null)) {\n return json;\n }\n return {\n \n ...json,\n 'tenant': json['tenant'],\n 'name': json['name'],\n 'logo': !exists(json, 'logo') ? undefined : json['logo'],\n 'homepage': !exists(json, 'homepage') ? undefined : json['homepage'],\n 'twitter': !exists(json, 'twitter') ? undefined : json['twitter'],\n 'facebook': !exists(json, 'facebook') ? undefined : json['facebook'],\n 'instagram': !exists(json, 'instagram') ? undefined : json['instagram'],\n 'linkedin': !exists(json, 'linkedin') ? undefined : json['linkedin'],\n 'location': !exists(json, 'location') ? undefined : HellewiLocationFromJSON(json['location']),\n 'phone': !exists(json, 'phone') ? undefined : json['phone'],\n 'email': !exists(json, 'email') ? undefined : json['email'],\n };\n}\n\nexport function HellewiTenantToJSON(value?: HellewiTenant | null): any {\n if (value === undefined) {\n return undefined;\n }\n if (value === null) {\n return null;\n }\n return {\n \n ...value,\n 'tenant': value.tenant,\n 'name': value.name,\n 'logo': value.logo,\n 'homepage': value.homepage,\n 'twitter': value.twitter,\n 'facebook': value.facebook,\n 'instagram': value.instagram,\n 'linkedin': value.linkedin,\n 'location': HellewiLocationToJSON(value.location),\n 'phone': value.phone,\n 'email': value.email,\n };\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` - `:<` 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 ### 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 \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\nimport * as runtime from '../runtime';\nimport {\n CatalogItemNotSupportedError,\n CatalogItemNotSupportedErrorFromJSON,\n CatalogItemNotSupportedErrorToJSON,\n ErrorResponse,\n ErrorResponseFromJSON,\n ErrorResponseToJSON,\n HellewiCatalogItemText,\n HellewiCatalogItemTextFromJSON,\n HellewiCatalogItemTextToJSON,\n HellewiFooter,\n HellewiFooterFromJSON,\n HellewiFooterToJSON,\n HellewiHeader,\n HellewiHeaderFromJSON,\n HellewiHeaderToJSON,\n HellewiHero,\n HellewiHeroFromJSON,\n HellewiHeroToJSON,\n HellewiPromotion,\n HellewiPromotionFromJSON,\n HellewiPromotionToJSON,\n HellewiText,\n HellewiTextFromJSON,\n HellewiTextToJSON,\n} from '../models';\n\nexport interface GetCatalogItemDetailsRequest {\n keyword: string;\n}\n\n/**\n * BrandApi - interface\n * @export\n * @interface BrandApiInterface\n */\nexport interface BrandApiInterface {\n /**\n * Get name and description for catalog-item\n * @param {string} keyword \n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof BrandApiInterface\n */\n getCatalogItemDetailsRaw(requestParameters: GetCatalogItemDetailsRequest): Promise>;\n\n /**\n * Get name and description for catalog-item\n */\n getCatalogItemDetails(requestParameters: GetCatalogItemDetailsRequest): Promise;\n\n /**\n * Tenant\\'s brand information to footer\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof BrandApiInterface\n */\n getFooterRaw(): Promise>;\n\n /**\n * Tenant\\'s brand information to footer\n */\n getFooter(): Promise;\n\n /**\n * Tenant\\'s brand information to header\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof BrandApiInterface\n */\n getHeaderRaw(): Promise>;\n\n /**\n * Tenant\\'s brand information to header\n */\n getHeader(): Promise;\n\n /**\n * Tenant\\'s help page text\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof BrandApiInterface\n */\n getHelpRaw(): Promise>;\n\n /**\n * Tenant\\'s help page text\n */\n getHelp(): Promise;\n\n /**\n * Tenant\\'s brand information to hero element\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof BrandApiInterface\n */\n getHeroRaw(): Promise>;\n\n /**\n * Tenant\\'s brand information to hero element\n */\n getHero(): Promise;\n\n /**\n * Tenant\\'s brand information to hero element\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof BrandApiInterface\n */\n listPromotionsRaw(): Promise>>;\n\n /**\n * Tenant\\'s brand information to hero element\n */\n listPromotions(): Promise>;\n\n}\n\n/**\n * no description\n */\nexport class BrandApi extends runtime.BaseAPI implements BrandApiInterface {\n\n /**\n * Get name and description for catalog-item\n */\n async getCatalogItemDetailsRaw(requestParameters: GetCatalogItemDetailsRequest): Promise> {\n if (requestParameters.keyword === null || requestParameters.keyword === undefined) {\n throw new runtime.RequiredError('keyword','Required parameter requestParameters.keyword was null or undefined when calling getCatalogItemDetails.');\n }\n\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/brand/catalog-item/{keyword}`.replace(`{${\"keyword\"}}`, encodeURIComponent(String(requestParameters.keyword))),\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiCatalogItemTextFromJSON(jsonValue));\n }\n\n /**\n * Get name and description for catalog-item\n */\n async getCatalogItemDetails(requestParameters: GetCatalogItemDetailsRequest): Promise {\n const response = await this.getCatalogItemDetailsRaw(requestParameters);\n return await response.value();\n }\n\n /**\n * Tenant\\'s brand information to footer\n */\n async getFooterRaw(): Promise> {\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/brand/footer`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiFooterFromJSON(jsonValue));\n }\n\n /**\n * Tenant\\'s brand information to footer\n */\n async getFooter(): Promise {\n const response = await this.getFooterRaw();\n return await response.value();\n }\n\n /**\n * Tenant\\'s brand information to header\n */\n async getHeaderRaw(): Promise> {\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/brand/header`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiHeaderFromJSON(jsonValue));\n }\n\n /**\n * Tenant\\'s brand information to header\n */\n async getHeader(): Promise {\n const response = await this.getHeaderRaw();\n return await response.value();\n }\n\n /**\n * Tenant\\'s help page text\n */\n async getHelpRaw(): Promise> {\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/brand/help`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiTextFromJSON(jsonValue));\n }\n\n /**\n * Tenant\\'s help page text\n */\n async getHelp(): Promise {\n const response = await this.getHelpRaw();\n return await response.value();\n }\n\n /**\n * Tenant\\'s brand information to hero element\n */\n async getHeroRaw(): Promise> {\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/brand/hero`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiHeroFromJSON(jsonValue));\n }\n\n /**\n * Tenant\\'s brand information to hero element\n */\n async getHero(): Promise {\n const response = await this.getHeroRaw();\n return await response.value();\n }\n\n /**\n * Tenant\\'s brand information to hero element\n */\n async listPromotionsRaw(): Promise>> {\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/brand/promotions`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(HellewiPromotionFromJSON));\n }\n\n /**\n * Tenant\\'s brand information to hero element\n */\n async listPromotions(): Promise> {\n const response = await this.listPromotionsRaw();\n return await response.value();\n }\n\n}\n","import {\n computed,\n ComputedRef,\n onBeforeMount,\n ref,\n Ref,\n watch\n} from '@vue/composition-api';\nimport { SnackbarProgrammatic as Snackbar } from 'buefy';\nimport { BNoticeComponent } from 'buefy/types/components';\n\nimport { Configuration } from '../api';\n\nimport { translate } from './misc-utils';\n\nexport enum RequestState {\n Uninitialized = 'UNINITIALIZED',\n Initialized = 'INITIALIZED',\n Loading = 'LOADING',\n Success = 'SUCCESS',\n Error = 'ERROR'\n}\n\nexport type Api = () => {\n api: Ref;\n changeConfiguration: (configuration: Configuration) => void;\n};\n\nexport type ApiEndpoint = () => {\n initial: O;\n state: Ref;\n response: Ref;\n execute: (input: I) => void;\n // hasError and isLoading would fit here, but unfortunately watchers' and\n // computed variables' lifecycle is limited to the component in which they\n // are loaded, so their watchers will be stopped when the component is\n // unmounted.\n //\n // So they have to be created for each component separately like this:\n // const { response: course, execute: getCourse, state } = useGetCourse();\n // const isLoading = stateIsLoading(state);\n};\n\nexport const stateHasError = (state: Ref): ComputedRef =>\n computed(() => state.value === RequestState.Error);\n\nexport const stateIsLoading = (\n state: Ref\n): ComputedRef => computed(() => state.value === RequestState.Loading);\n\nexport const ApiEndpointInitialization = (\n api: Ref,\n state: Ref,\n response: Ref,\n initial: O\n) => {\n const initialize = () => {\n if (api.value) {\n state.value = RequestState.Initialized;\n } else {\n state.value = RequestState.Uninitialized;\n }\n response.value = initial;\n };\n\n onBeforeMount(() => {\n if (state.value === RequestState.Uninitialized) {\n initialize();\n }\n });\n watch(api, initialize); // if API is changed, reset everything\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const useErrorToast = (ctx: any) => {\n const warnComponents = ref([]);\n const warnToast = (i18nKey: string) =>\n warnComponents.value.push(\n Snackbar.open({\n message: translate(ctx, i18nKey),\n duration: 5000,\n type: 'is-warning',\n position: 'is-top',\n actionText: 'OK',\n indefinite: true,\n queue: true\n })\n );\n\n const clearErrorToasts = () => {\n for (const component of warnComponents.value) {\n component.close();\n }\n warnComponents.value = [];\n };\n\n return { warnToast, clearErrorToasts };\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` - `:<` 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 ### 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 \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\nimport * as runtime from '../runtime';\nimport {\n ErrorResponse,\n ErrorResponseFromJSON,\n ErrorResponseToJSON,\n HellewiCatalog,\n HellewiCatalogFromJSON,\n HellewiCatalogToJSON,\n HellewiCatalogSettings,\n HellewiCatalogSettingsFromJSON,\n HellewiCatalogSettingsToJSON,\n} from '../models';\n\nexport interface GetCatalogRequest {\n q?: string;\n}\n\n/**\n * CatalogApi - interface\n * @export\n * @interface CatalogApiInterface\n */\nexport interface CatalogApiInterface {\n /**\n * List of catalog items (e.g. subject) that can be used for filtering courses. Different items are grouped together in the response. ``` Subject - [ ] Philosophy, 3 courses - [ ] French, 3 courses - [ ] German, 1 course Location - [ ] Ahjola, 2 courses - [ ] Sampola, 4 courses Weekday (*1) - [ ] Monday, 1 course - [ ] Tuesday, 2 courses - [ ] Thursday, 1 course - [ ] Sunday, 3 courses ``` - **1:** A course can have multiple catalog items of some catalog item categories, such as weekdays (e.g. a single course can be held on Mondays and Tuesdays). ### Catalog filtering The response is filtered according to given search query: course count matches the query, and catalog items that don\\'t have any matching courses are omitted. There is one exception to the rule above: if a subject is selected for example, the response subject includes *all* subjects and not just the selected ones. This allows to create the following kind of catalog structure (philosophy is selected, query something like `q=subject:5`): ``` Subject - [x] Philosophy, 3 courses - [ ] French, 3 courses (*1) - [ ] German, 1 course (*1) Location - [ ] Ahjola, 1 course - [ ] Sampola, 2 courses Weekday - [ ] Tuesday, 2 courses - [ ] Sunday, 1 courses ``` - **1:** Here French and German are included in the results, even though the three courses that match philosophy don\\'t match the languages. If multiple items from different categories are selected, result will be filtered so that for a single catalog item group, all other filters except its own apply to that group (`q:subject:5+location:2`): ``` Subject - [x] Philosophy, 2 courses (*1) Location - [ ] Ahjola, 1 course (*2) - [x] Sampola, 2 courses Weekday - [ ] Tuesday, 1 course - [ ] Sunday, 1 course ``` - **1:** French and German are omitted because all courses in Sampola are philosophy, and philosophy has only two courses that are in Sampola. - **2:** Ahjola is included because there would be a third philosophy course. ### Tree structure in catalog All the catalog item groups are arrays of depth one, but HellewiCatalogItem objects contain parent information that can be used to create a tree structure of those catalog items. ``` Department, Category, Subject - [ ] Mäntsälä, 4 courses - [ ] Psychology and pedagogy, 1 course - [ ] Psychology, 1 course - [ ] Languages, 4 courses - [ ] French, 3 courses - [ ] German, 1 course - [ ] Pornainen, 2 courses - [ ] Psychology and pedagogy, 2 courses - [ ] Psychology, 2 courses ``` This can be created so that for each item in departments, search for all items in categories that have that department\\'s keyword as parent. And continue with each of those categories matching parents from subjects. Following parent-child -chains are possible: - Department - Category - Subject - Category - Subject - Term - Period - Classification - Education sector Term - Period and Classification - Education sector are simple so that the relationship is always 1:n, i.e. a period will always have a term as parent, and there cannot be duplicate periods with different parents. Department - Category - Subject is complex. Relationships are n:m, i.e. a category can have different departments as parent (for example language courses are taught both in Mäntsälä and Pornainen). Furthermore, the response includes information so that depth 1 (subject-only), 2 (category-subject) and 3 (department-category-subject) catalog trees can be built. The keywords are also different for these different depth options. For example subject for: - depth 1 will have one id: `subject:34`, - depth 2 will have two ids: `subject:7/34`, this also implies parent `category:7` - depth 3 will have three: `subject:2/7/34`, this also implies parent `category:2/7`, and furthermore category\\'s parent `department:2` (but this is not included in the subject catalog item, only in the parent category) Categories are also different for depth 2 and 3. The simple algorithm for building these is to start from the top and select those items that have parent: null, and then continue with the children that have matching parents. ### Tree structure and filtering The rule that filtering applies to all other catalog item groups except the selected one has some implications when building a tree structured catalog. For example, selecting Mäntsälä - Psycholog and pedagogy - Psychology, `q=subject:1/1/1`: ``` Department, Category, Subject - [ ] Mäntsälä, 1 course (*1) - [ ] Psychology and pedagogy, 1 course (*3) - [x] Psychology, 1 course - [ ] Languages, 0 courses (*4) - [ ] French, 3 courses (*6) - [ ] German, 1 courses - [ ] Pornainen, 0 courses (*2) - [ ] Psychology and pedagogy, 0 courses (*5) - [ ] Psychology, 2 courses (*7) ``` - **1:** Mäntsälä (`department:1`) is included in the response, as the psychology course matches this department. Course count is 1 as there is one psychology course. - **2:** Pornainen (`department:2`) is *not included* in the response `subject:1/1/1`-courses don\\'t match Pornainen. - **3:** Mäntsälä\\'s Psychology and pedagogy (`category:1/1`) is included in the response with course count 1. - **4:** Mäntsälä\\'s Languages (`category:1/2`) is *not included* in the response. - **5:** Pornainen\\'s Psychology and pedagogy (`category:2/1`) is *not included* in the response. - **6:** Mäntsälä-Languages-French and (`subject:1/2/1`) and German (`subject:1/2/2`) *are included* in the response, as the subject filtering doesn\\'t apply to other subjects. This point can be counter-intuitive when used in tree structure. - **7:** Pornainen-Psychology and pedagogy-Psychology (`subject:2/1/1`) also *is included* in the response. Depending on which kind of user interface is being built, this tree probably cannot be built only from a filtered response, but rather the filtered and unfiltered response have to be combined. For this kind of depth 3 catalog, it would probably be the simplest to add only catalog items with type subject to search query (e.g. selecting Mäntsälä selects all subjects under it and doesn\\'t add the department or its categories). Then also the course counts for deparments and categories could be calculated from response subjects. And the departments and categores would have to be saved from the unfiltered response as the filtered responses don\\'t have the unmatching ones included.\n * @param {string} [q] Search query, see instructions in [Search](#section/Search).\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof CatalogApiInterface\n */\n getCatalogRaw(requestParameters: GetCatalogRequest): Promise>;\n\n /**\n * List of catalog items (e.g. subject) that can be used for filtering courses. Different items are grouped together in the response. ``` Subject - [ ] Philosophy, 3 courses - [ ] French, 3 courses - [ ] German, 1 course Location - [ ] Ahjola, 2 courses - [ ] Sampola, 4 courses Weekday (*1) - [ ] Monday, 1 course - [ ] Tuesday, 2 courses - [ ] Thursday, 1 course - [ ] Sunday, 3 courses ``` - **1:** A course can have multiple catalog items of some catalog item categories, such as weekdays (e.g. a single course can be held on Mondays and Tuesdays). ### Catalog filtering The response is filtered according to given search query: course count matches the query, and catalog items that don\\'t have any matching courses are omitted. There is one exception to the rule above: if a subject is selected for example, the response subject includes *all* subjects and not just the selected ones. This allows to create the following kind of catalog structure (philosophy is selected, query something like `q=subject:5`): ``` Subject - [x] Philosophy, 3 courses - [ ] French, 3 courses (*1) - [ ] German, 1 course (*1) Location - [ ] Ahjola, 1 course - [ ] Sampola, 2 courses Weekday - [ ] Tuesday, 2 courses - [ ] Sunday, 1 courses ``` - **1:** Here French and German are included in the results, even though the three courses that match philosophy don\\'t match the languages. If multiple items from different categories are selected, result will be filtered so that for a single catalog item group, all other filters except its own apply to that group (`q:subject:5+location:2`): ``` Subject - [x] Philosophy, 2 courses (*1) Location - [ ] Ahjola, 1 course (*2) - [x] Sampola, 2 courses Weekday - [ ] Tuesday, 1 course - [ ] Sunday, 1 course ``` - **1:** French and German are omitted because all courses in Sampola are philosophy, and philosophy has only two courses that are in Sampola. - **2:** Ahjola is included because there would be a third philosophy course. ### Tree structure in catalog All the catalog item groups are arrays of depth one, but HellewiCatalogItem objects contain parent information that can be used to create a tree structure of those catalog items. ``` Department, Category, Subject - [ ] Mäntsälä, 4 courses - [ ] Psychology and pedagogy, 1 course - [ ] Psychology, 1 course - [ ] Languages, 4 courses - [ ] French, 3 courses - [ ] German, 1 course - [ ] Pornainen, 2 courses - [ ] Psychology and pedagogy, 2 courses - [ ] Psychology, 2 courses ``` This can be created so that for each item in departments, search for all items in categories that have that department\\'s keyword as parent. And continue with each of those categories matching parents from subjects. Following parent-child -chains are possible: - Department - Category - Subject - Category - Subject - Term - Period - Classification - Education sector Term - Period and Classification - Education sector are simple so that the relationship is always 1:n, i.e. a period will always have a term as parent, and there cannot be duplicate periods with different parents. Department - Category - Subject is complex. Relationships are n:m, i.e. a category can have different departments as parent (for example language courses are taught both in Mäntsälä and Pornainen). Furthermore, the response includes information so that depth 1 (subject-only), 2 (category-subject) and 3 (department-category-subject) catalog trees can be built. The keywords are also different for these different depth options. For example subject for: - depth 1 will have one id: `subject:34`, - depth 2 will have two ids: `subject:7/34`, this also implies parent `category:7` - depth 3 will have three: `subject:2/7/34`, this also implies parent `category:2/7`, and furthermore category\\'s parent `department:2` (but this is not included in the subject catalog item, only in the parent category) Categories are also different for depth 2 and 3. The simple algorithm for building these is to start from the top and select those items that have parent: null, and then continue with the children that have matching parents. ### Tree structure and filtering The rule that filtering applies to all other catalog item groups except the selected one has some implications when building a tree structured catalog. For example, selecting Mäntsälä - Psycholog and pedagogy - Psychology, `q=subject:1/1/1`: ``` Department, Category, Subject - [ ] Mäntsälä, 1 course (*1) - [ ] Psychology and pedagogy, 1 course (*3) - [x] Psychology, 1 course - [ ] Languages, 0 courses (*4) - [ ] French, 3 courses (*6) - [ ] German, 1 courses - [ ] Pornainen, 0 courses (*2) - [ ] Psychology and pedagogy, 0 courses (*5) - [ ] Psychology, 2 courses (*7) ``` - **1:** Mäntsälä (`department:1`) is included in the response, as the psychology course matches this department. Course count is 1 as there is one psychology course. - **2:** Pornainen (`department:2`) is *not included* in the response `subject:1/1/1`-courses don\\'t match Pornainen. - **3:** Mäntsälä\\'s Psychology and pedagogy (`category:1/1`) is included in the response with course count 1. - **4:** Mäntsälä\\'s Languages (`category:1/2`) is *not included* in the response. - **5:** Pornainen\\'s Psychology and pedagogy (`category:2/1`) is *not included* in the response. - **6:** Mäntsälä-Languages-French and (`subject:1/2/1`) and German (`subject:1/2/2`) *are included* in the response, as the subject filtering doesn\\'t apply to other subjects. This point can be counter-intuitive when used in tree structure. - **7:** Pornainen-Psychology and pedagogy-Psychology (`subject:2/1/1`) also *is included* in the response. Depending on which kind of user interface is being built, this tree probably cannot be built only from a filtered response, but rather the filtered and unfiltered response have to be combined. For this kind of depth 3 catalog, it would probably be the simplest to add only catalog items with type subject to search query (e.g. selecting Mäntsälä selects all subjects under it and doesn\\'t add the department or its categories). Then also the course counts for deparments and categories could be calculated from response subjects. And the departments and categores would have to be saved from the unfiltered response as the filtered responses don\\'t have the unmatching ones included.\n */\n getCatalog(requestParameters: GetCatalogRequest): Promise;\n\n /**\n * Catalog settings\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof CatalogApiInterface\n */\n getCatalogSettingsRaw(): Promise>;\n\n /**\n * Catalog settings\n */\n getCatalogSettings(): Promise;\n\n}\n\n/**\n * no description\n */\nexport class CatalogApi extends runtime.BaseAPI implements CatalogApiInterface {\n\n /**\n * List of catalog items (e.g. subject) that can be used for filtering courses. Different items are grouped together in the response. ``` Subject - [ ] Philosophy, 3 courses - [ ] French, 3 courses - [ ] German, 1 course Location - [ ] Ahjola, 2 courses - [ ] Sampola, 4 courses Weekday (*1) - [ ] Monday, 1 course - [ ] Tuesday, 2 courses - [ ] Thursday, 1 course - [ ] Sunday, 3 courses ``` - **1:** A course can have multiple catalog items of some catalog item categories, such as weekdays (e.g. a single course can be held on Mondays and Tuesdays). ### Catalog filtering The response is filtered according to given search query: course count matches the query, and catalog items that don\\'t have any matching courses are omitted. There is one exception to the rule above: if a subject is selected for example, the response subject includes *all* subjects and not just the selected ones. This allows to create the following kind of catalog structure (philosophy is selected, query something like `q=subject:5`): ``` Subject - [x] Philosophy, 3 courses - [ ] French, 3 courses (*1) - [ ] German, 1 course (*1) Location - [ ] Ahjola, 1 course - [ ] Sampola, 2 courses Weekday - [ ] Tuesday, 2 courses - [ ] Sunday, 1 courses ``` - **1:** Here French and German are included in the results, even though the three courses that match philosophy don\\'t match the languages. If multiple items from different categories are selected, result will be filtered so that for a single catalog item group, all other filters except its own apply to that group (`q:subject:5+location:2`): ``` Subject - [x] Philosophy, 2 courses (*1) Location - [ ] Ahjola, 1 course (*2) - [x] Sampola, 2 courses Weekday - [ ] Tuesday, 1 course - [ ] Sunday, 1 course ``` - **1:** French and German are omitted because all courses in Sampola are philosophy, and philosophy has only two courses that are in Sampola. - **2:** Ahjola is included because there would be a third philosophy course. ### Tree structure in catalog All the catalog item groups are arrays of depth one, but HellewiCatalogItem objects contain parent information that can be used to create a tree structure of those catalog items. ``` Department, Category, Subject - [ ] Mäntsälä, 4 courses - [ ] Psychology and pedagogy, 1 course - [ ] Psychology, 1 course - [ ] Languages, 4 courses - [ ] French, 3 courses - [ ] German, 1 course - [ ] Pornainen, 2 courses - [ ] Psychology and pedagogy, 2 courses - [ ] Psychology, 2 courses ``` This can be created so that for each item in departments, search for all items in categories that have that department\\'s keyword as parent. And continue with each of those categories matching parents from subjects. Following parent-child -chains are possible: - Department - Category - Subject - Category - Subject - Term - Period - Classification - Education sector Term - Period and Classification - Education sector are simple so that the relationship is always 1:n, i.e. a period will always have a term as parent, and there cannot be duplicate periods with different parents. Department - Category - Subject is complex. Relationships are n:m, i.e. a category can have different departments as parent (for example language courses are taught both in Mäntsälä and Pornainen). Furthermore, the response includes information so that depth 1 (subject-only), 2 (category-subject) and 3 (department-category-subject) catalog trees can be built. The keywords are also different for these different depth options. For example subject for: - depth 1 will have one id: `subject:34`, - depth 2 will have two ids: `subject:7/34`, this also implies parent `category:7` - depth 3 will have three: `subject:2/7/34`, this also implies parent `category:2/7`, and furthermore category\\'s parent `department:2` (but this is not included in the subject catalog item, only in the parent category) Categories are also different for depth 2 and 3. The simple algorithm for building these is to start from the top and select those items that have parent: null, and then continue with the children that have matching parents. ### Tree structure and filtering The rule that filtering applies to all other catalog item groups except the selected one has some implications when building a tree structured catalog. For example, selecting Mäntsälä - Psycholog and pedagogy - Psychology, `q=subject:1/1/1`: ``` Department, Category, Subject - [ ] Mäntsälä, 1 course (*1) - [ ] Psychology and pedagogy, 1 course (*3) - [x] Psychology, 1 course - [ ] Languages, 0 courses (*4) - [ ] French, 3 courses (*6) - [ ] German, 1 courses - [ ] Pornainen, 0 courses (*2) - [ ] Psychology and pedagogy, 0 courses (*5) - [ ] Psychology, 2 courses (*7) ``` - **1:** Mäntsälä (`department:1`) is included in the response, as the psychology course matches this department. Course count is 1 as there is one psychology course. - **2:** Pornainen (`department:2`) is *not included* in the response `subject:1/1/1`-courses don\\'t match Pornainen. - **3:** Mäntsälä\\'s Psychology and pedagogy (`category:1/1`) is included in the response with course count 1. - **4:** Mäntsälä\\'s Languages (`category:1/2`) is *not included* in the response. - **5:** Pornainen\\'s Psychology and pedagogy (`category:2/1`) is *not included* in the response. - **6:** Mäntsälä-Languages-French and (`subject:1/2/1`) and German (`subject:1/2/2`) *are included* in the response, as the subject filtering doesn\\'t apply to other subjects. This point can be counter-intuitive when used in tree structure. - **7:** Pornainen-Psychology and pedagogy-Psychology (`subject:2/1/1`) also *is included* in the response. Depending on which kind of user interface is being built, this tree probably cannot be built only from a filtered response, but rather the filtered and unfiltered response have to be combined. For this kind of depth 3 catalog, it would probably be the simplest to add only catalog items with type subject to search query (e.g. selecting Mäntsälä selects all subjects under it and doesn\\'t add the department or its categories). Then also the course counts for deparments and categories could be calculated from response subjects. And the departments and categores would have to be saved from the unfiltered response as the filtered responses don\\'t have the unmatching ones included.\n */\n async getCatalogRaw(requestParameters: GetCatalogRequest): Promise> {\n const queryParameters: runtime.HTTPQuery = {};\n\n if (requestParameters.q !== undefined) {\n queryParameters['q'] = requestParameters.q;\n }\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/catalog`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiCatalogFromJSON(jsonValue));\n }\n\n /**\n * List of catalog items (e.g. subject) that can be used for filtering courses. Different items are grouped together in the response. ``` Subject - [ ] Philosophy, 3 courses - [ ] French, 3 courses - [ ] German, 1 course Location - [ ] Ahjola, 2 courses - [ ] Sampola, 4 courses Weekday (*1) - [ ] Monday, 1 course - [ ] Tuesday, 2 courses - [ ] Thursday, 1 course - [ ] Sunday, 3 courses ``` - **1:** A course can have multiple catalog items of some catalog item categories, such as weekdays (e.g. a single course can be held on Mondays and Tuesdays). ### Catalog filtering The response is filtered according to given search query: course count matches the query, and catalog items that don\\'t have any matching courses are omitted. There is one exception to the rule above: if a subject is selected for example, the response subject includes *all* subjects and not just the selected ones. This allows to create the following kind of catalog structure (philosophy is selected, query something like `q=subject:5`): ``` Subject - [x] Philosophy, 3 courses - [ ] French, 3 courses (*1) - [ ] German, 1 course (*1) Location - [ ] Ahjola, 1 course - [ ] Sampola, 2 courses Weekday - [ ] Tuesday, 2 courses - [ ] Sunday, 1 courses ``` - **1:** Here French and German are included in the results, even though the three courses that match philosophy don\\'t match the languages. If multiple items from different categories are selected, result will be filtered so that for a single catalog item group, all other filters except its own apply to that group (`q:subject:5+location:2`): ``` Subject - [x] Philosophy, 2 courses (*1) Location - [ ] Ahjola, 1 course (*2) - [x] Sampola, 2 courses Weekday - [ ] Tuesday, 1 course - [ ] Sunday, 1 course ``` - **1:** French and German are omitted because all courses in Sampola are philosophy, and philosophy has only two courses that are in Sampola. - **2:** Ahjola is included because there would be a third philosophy course. ### Tree structure in catalog All the catalog item groups are arrays of depth one, but HellewiCatalogItem objects contain parent information that can be used to create a tree structure of those catalog items. ``` Department, Category, Subject - [ ] Mäntsälä, 4 courses - [ ] Psychology and pedagogy, 1 course - [ ] Psychology, 1 course - [ ] Languages, 4 courses - [ ] French, 3 courses - [ ] German, 1 course - [ ] Pornainen, 2 courses - [ ] Psychology and pedagogy, 2 courses - [ ] Psychology, 2 courses ``` This can be created so that for each item in departments, search for all items in categories that have that department\\'s keyword as parent. And continue with each of those categories matching parents from subjects. Following parent-child -chains are possible: - Department - Category - Subject - Category - Subject - Term - Period - Classification - Education sector Term - Period and Classification - Education sector are simple so that the relationship is always 1:n, i.e. a period will always have a term as parent, and there cannot be duplicate periods with different parents. Department - Category - Subject is complex. Relationships are n:m, i.e. a category can have different departments as parent (for example language courses are taught both in Mäntsälä and Pornainen). Furthermore, the response includes information so that depth 1 (subject-only), 2 (category-subject) and 3 (department-category-subject) catalog trees can be built. The keywords are also different for these different depth options. For example subject for: - depth 1 will have one id: `subject:34`, - depth 2 will have two ids: `subject:7/34`, this also implies parent `category:7` - depth 3 will have three: `subject:2/7/34`, this also implies parent `category:2/7`, and furthermore category\\'s parent `department:2` (but this is not included in the subject catalog item, only in the parent category) Categories are also different for depth 2 and 3. The simple algorithm for building these is to start from the top and select those items that have parent: null, and then continue with the children that have matching parents. ### Tree structure and filtering The rule that filtering applies to all other catalog item groups except the selected one has some implications when building a tree structured catalog. For example, selecting Mäntsälä - Psycholog and pedagogy - Psychology, `q=subject:1/1/1`: ``` Department, Category, Subject - [ ] Mäntsälä, 1 course (*1) - [ ] Psychology and pedagogy, 1 course (*3) - [x] Psychology, 1 course - [ ] Languages, 0 courses (*4) - [ ] French, 3 courses (*6) - [ ] German, 1 courses - [ ] Pornainen, 0 courses (*2) - [ ] Psychology and pedagogy, 0 courses (*5) - [ ] Psychology, 2 courses (*7) ``` - **1:** Mäntsälä (`department:1`) is included in the response, as the psychology course matches this department. Course count is 1 as there is one psychology course. - **2:** Pornainen (`department:2`) is *not included* in the response `subject:1/1/1`-courses don\\'t match Pornainen. - **3:** Mäntsälä\\'s Psychology and pedagogy (`category:1/1`) is included in the response with course count 1. - **4:** Mäntsälä\\'s Languages (`category:1/2`) is *not included* in the response. - **5:** Pornainen\\'s Psychology and pedagogy (`category:2/1`) is *not included* in the response. - **6:** Mäntsälä-Languages-French and (`subject:1/2/1`) and German (`subject:1/2/2`) *are included* in the response, as the subject filtering doesn\\'t apply to other subjects. This point can be counter-intuitive when used in tree structure. - **7:** Pornainen-Psychology and pedagogy-Psychology (`subject:2/1/1`) also *is included* in the response. Depending on which kind of user interface is being built, this tree probably cannot be built only from a filtered response, but rather the filtered and unfiltered response have to be combined. For this kind of depth 3 catalog, it would probably be the simplest to add only catalog items with type subject to search query (e.g. selecting Mäntsälä selects all subjects under it and doesn\\'t add the department or its categories). Then also the course counts for deparments and categories could be calculated from response subjects. And the departments and categores would have to be saved from the unfiltered response as the filtered responses don\\'t have the unmatching ones included.\n */\n async getCatalog(requestParameters: GetCatalogRequest): Promise {\n const response = await this.getCatalogRaw(requestParameters);\n return await response.value();\n }\n\n /**\n * Catalog settings\n */\n async getCatalogSettingsRaw(): Promise> {\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/catalog/settings`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiCatalogSettingsFromJSON(jsonValue));\n }\n\n /**\n * Catalog settings\n */\n async getCatalogSettings(): Promise {\n const response = await this.getCatalogSettingsRaw();\n return await response.value();\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` - `:<` 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 ### 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 \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\nimport * as runtime from '../runtime';\nimport {\n ErrorResponse,\n ErrorResponseFromJSON,\n ErrorResponseToJSON,\n HellewiCourse,\n HellewiCourseFromJSON,\n HellewiCourseToJSON,\n HellewiCourseCount,\n HellewiCourseCountFromJSON,\n HellewiCourseCountToJSON,\n HellewiCoursePartial,\n HellewiCoursePartialFromJSON,\n HellewiCoursePartialToJSON,\n HellewiParticipantCount,\n HellewiParticipantCountFromJSON,\n HellewiParticipantCountToJSON,\n} from '../models';\n\nexport interface GetCourseRequest {\n id: string;\n}\n\nexport interface GetCourseCountRequest {\n q?: string;\n}\n\nexport interface ListCourseParticipantCountsRequest {\n ids?: Array;\n}\n\nexport interface ListCoursesRequest {\n q?: string;\n page?: number;\n limit?: number;\n sort?: Array;\n sortdir?: string;\n}\n\n/**\n * CourseApi - interface\n * @export\n * @interface CourseApiInterface\n */\nexport interface CourseApiInterface {\n /**\n * Course information\n * @param {string} id \n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof CourseApiInterface\n */\n getCourseRaw(requestParameters: GetCourseRequest): Promise>;\n\n /**\n * Course information\n */\n getCourse(requestParameters: GetCourseRequest): Promise;\n\n /**\n * Course count Response includes also `x-total-count` header, which is explained in [Pagination](#section/Search/Pagination) (except that from this endpoint there is no 10000 limit).\n * @param {string} [q] Search query, see instructions in [Search](#section/Search).\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof CourseApiInterface\n */\n getCourseCountRaw(requestParameters: GetCourseCountRequest): Promise>;\n\n /**\n * Course count Response includes also `x-total-count` header, which is explained in [Pagination](#section/Search/Pagination) (except that from this endpoint there is no 10000 limit).\n */\n getCourseCount(requestParameters: GetCourseCountRequest): Promise;\n\n /**\n * List participant counts in courses Optional fields in response will always be there if global parameter registrationsettings.showseatcount is set to true, or if course parameter showplacecount is set to true Note that the maximum length of an URL (recommendation is 2000 characters) can become a limitation here if there are 100 course ids in multi-tenant form. In this case, use multiple requests for fetching the participant counts.\n * @param {Array} [ids] Course ids\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof CourseApiInterface\n */\n listCourseParticipantCountsRaw(requestParameters: ListCourseParticipantCountsRequest): Promise>>;\n\n /**\n * List participant counts in courses Optional fields in response will always be there if global parameter registrationsettings.showseatcount is set to true, or if course parameter showplacecount is set to true Note that the maximum length of an URL (recommendation is 2000 characters) can become a limitation here if there are 100 course ids in multi-tenant form. In this case, use multiple requests for fetching the participant counts.\n */\n listCourseParticipantCounts(requestParameters: ListCourseParticipantCountsRequest): Promise>;\n\n /**\n * Course listing Response includes also `link` and `x-total-count` headers, which are explained in [Pagination](#section/Search/Pagination).\n * @param {string} [q] Search query, see instructions in [Search](#section/Search).\n * @param {number} [page] Pagination: wanted page starting from 1\n * @param {number} [limit] Pagination: how many items there are per page (maximum 100)\n * @param {Array} [sort] Result sorting: sort according to these fields, defaults to `\\'code\\'` if `q` is not given, otherwise sort best matching first\n * @param {string} [sortdir] Result sorting: sort direction, ascending or descending, defaults to `\\'asc\\'` if `\\'q\\'` is not given\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof CourseApiInterface\n */\n listCoursesRaw(requestParameters: ListCoursesRequest): Promise>>;\n\n /**\n * Course listing Response includes also `link` and `x-total-count` headers, which are explained in [Pagination](#section/Search/Pagination).\n */\n listCourses(requestParameters: ListCoursesRequest): Promise>;\n\n}\n\n/**\n * no description\n */\nexport class CourseApi extends runtime.BaseAPI implements CourseApiInterface {\n\n /**\n * Course information\n */\n async getCourseRaw(requestParameters: GetCourseRequest): Promise> {\n if (requestParameters.id === null || requestParameters.id === undefined) {\n throw new runtime.RequiredError('id','Required parameter requestParameters.id was null or undefined when calling getCourse.');\n }\n\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/courses/{id}`.replace(`{${\"id\"}}`, encodeURIComponent(String(requestParameters.id))),\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiCourseFromJSON(jsonValue));\n }\n\n /**\n * Course information\n */\n async getCourse(requestParameters: GetCourseRequest): Promise {\n const response = await this.getCourseRaw(requestParameters);\n return await response.value();\n }\n\n /**\n * Course count Response includes also `x-total-count` header, which is explained in [Pagination](#section/Search/Pagination) (except that from this endpoint there is no 10000 limit).\n */\n async getCourseCountRaw(requestParameters: GetCourseCountRequest): Promise> {\n const queryParameters: runtime.HTTPQuery = {};\n\n if (requestParameters.q !== undefined) {\n queryParameters['q'] = requestParameters.q;\n }\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/course-count`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => HellewiCourseCountFromJSON(jsonValue));\n }\n\n /**\n * Course count Response includes also `x-total-count` header, which is explained in [Pagination](#section/Search/Pagination) (except that from this endpoint there is no 10000 limit).\n */\n async getCourseCount(requestParameters: GetCourseCountRequest): Promise {\n const response = await this.getCourseCountRaw(requestParameters);\n return await response.value();\n }\n\n /**\n * List participant counts in courses Optional fields in response will always be there if global parameter registrationsettings.showseatcount is set to true, or if course parameter showplacecount is set to true Note that the maximum length of an URL (recommendation is 2000 characters) can become a limitation here if there are 100 course ids in multi-tenant form. In this case, use multiple requests for fetching the participant counts.\n */\n async listCourseParticipantCountsRaw(requestParameters: ListCourseParticipantCountsRequest): Promise>> {\n const queryParameters: runtime.HTTPQuery = {};\n\n if (requestParameters.ids) {\n queryParameters['ids'] = requestParameters.ids;\n }\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/course-participants`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(HellewiParticipantCountFromJSON));\n }\n\n /**\n * List participant counts in courses Optional fields in response will always be there if global parameter registrationsettings.showseatcount is set to true, or if course parameter showplacecount is set to true Note that the maximum length of an URL (recommendation is 2000 characters) can become a limitation here if there are 100 course ids in multi-tenant form. In this case, use multiple requests for fetching the participant counts.\n */\n async listCourseParticipantCounts(requestParameters: ListCourseParticipantCountsRequest): Promise> {\n const response = await this.listCourseParticipantCountsRaw(requestParameters);\n return await response.value();\n }\n\n /**\n * Course listing Response includes also `link` and `x-total-count` headers, which are explained in [Pagination](#section/Search/Pagination).\n */\n async listCoursesRaw(requestParameters: ListCoursesRequest): Promise>> {\n const queryParameters: runtime.HTTPQuery = {};\n\n if (requestParameters.q !== undefined) {\n queryParameters['q'] = requestParameters.q;\n }\n\n if (requestParameters.page !== undefined) {\n queryParameters['page'] = requestParameters.page;\n }\n\n if (requestParameters.limit !== undefined) {\n queryParameters['limit'] = requestParameters.limit;\n }\n\n if (requestParameters.sort) {\n queryParameters['sort'] = requestParameters.sort;\n }\n\n if (requestParameters.sortdir !== undefined) {\n queryParameters['sortdir'] = requestParameters.sortdir;\n }\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/courses`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(HellewiCoursePartialFromJSON));\n }\n\n /**\n * Course listing Response includes also `link` and `x-total-count` headers, which are explained in [Pagination](#section/Search/Pagination).\n */\n async listCourses(requestParameters: ListCoursesRequest): Promise> {\n const response = await this.listCoursesRaw(requestParameters);\n return await response.value();\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` - `:<` 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 ### 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 \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\nimport * as runtime from '../runtime';\nimport {\n HellewiTenant,\n HellewiTenantFromJSON,\n HellewiTenantToJSON,\n} from '../models';\n\n/**\n * TenantApi - interface\n * @export\n * @interface TenantApiInterface\n */\nexport interface TenantApiInterface {\n /**\n * Tenant listing Endpoint returns branding information for each tenant. For single-tenant request, this will return only that tenant\\'s information. For multi-tenant it will return all the tenants that used api key has access to.\n * @param {*} [options] Override http request option.\n * @throws {RequiredError}\n * @memberof TenantApiInterface\n */\n listTenantsRaw(): Promise>>;\n\n /**\n * Tenant listing Endpoint returns branding information for each tenant. For single-tenant request, this will return only that tenant\\'s information. For multi-tenant it will return all the tenants that used api key has access to.\n */\n listTenants(): Promise>;\n\n}\n\n/**\n * no description\n */\nexport class TenantApi extends runtime.BaseAPI implements TenantApiInterface {\n\n /**\n * Tenant listing Endpoint returns branding information for each tenant. For single-tenant request, this will return only that tenant\\'s information. For multi-tenant it will return all the tenants that used api key has access to.\n */\n async listTenantsRaw(): Promise>> {\n const queryParameters: runtime.HTTPQuery = {};\n\n const headerParameters: runtime.HTTPHeaders = {};\n\n if (this.configuration && this.configuration.apiKey) {\n headerParameters[\"Authorization\"] = this.configuration.apiKey(\"Authorization\"); // JWT authentication\n }\n\n const response = await this.request({\n path: `/tenants`,\n method: 'GET',\n headers: headerParameters,\n query: queryParameters,\n });\n\n return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(HellewiTenantFromJSON));\n }\n\n /**\n * Tenant listing Endpoint returns branding information for each tenant. For single-tenant request, this will return only that tenant\\'s information. For multi-tenant it will return all the tenants that used api key has access to.\n */\n async listTenants(): Promise> {\n const response = await this.listTenantsRaw();\n return await response.value();\n }\n\n}\n","export const filterUndefineds = (xs: (T | undefined)[]): T[] =>\n xs.filter((x) => x !== undefined) as T[];\n\n// context too difficult to type correctly here I guess\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const translate = (context: any, i18nKey: string) => {\n if (context.parent && context.parent.$t) {\n const translation = context.parent.$t(i18nKey);\n\n if (translation) {\n return translation.toString();\n }\n }\n return i18nKey;\n};\n","import { ref } from '@vue/composition-api';\nimport { find, isEmpty, isEqual, map, memoize } from 'lodash/fp';\nimport PCancelable from 'p-cancelable';\n\nimport {\n Configuration,\n CourseApi,\n CourseApiInterface,\n HellewiCourse,\n HellewiCourseCount,\n HellewiCoursePartial,\n HellewiParticipantCount,\n HellewiLocation\n} from '../api';\n\nimport {\n Api,\n ApiEndpoint,\n ApiEndpointInitialization,\n RequestState\n} from '../utils/api-utils';\nimport { filterUndefineds } from '../utils/misc-utils';\n\n/**\n * Use course API\n *\n */\nexport const useCourseApi: Api = memoize(() => {\n const api = ref(undefined);\n\n const changeConfiguration = (configuration: Configuration) => {\n api.value = new CourseApi(configuration);\n };\n\n return {\n api,\n changeConfiguration\n };\n});\n\nexport const useGetCourseCount: ApiEndpoint<\n void,\n HellewiCourseCount | undefined\n> = memoize(() => {\n const initial = undefined;\n const { api } = useCourseApi();\n const state = ref(RequestState.Uninitialized);\n const response = ref(initial);\n\n ApiEndpointInitialization(api, state, response, initial);\n\n const execute = async () => {\n if (\n !api.value ||\n state.value === RequestState.Uninitialized ||\n // request already ongoing, don't start a new one\n state.value === RequestState.Loading ||\n // don't load again if this is already successfully loaded\n state.value === RequestState.Success\n ) {\n return;\n }\n\n try {\n state.value = RequestState.Loading;\n response.value = await api.value.getCourseCount({});\n state.value = RequestState.Success;\n } catch {\n response.value = initial;\n state.value = RequestState.Error;\n }\n };\n\n return {\n initial,\n state,\n response,\n execute\n };\n});\n\nexport const useGetCourse: ApiEndpoint<\n string,\n HellewiCourse | undefined\n> = memoize(() => {\n const initial = undefined;\n const { api } = useCourseApi();\n const state = ref(RequestState.Uninitialized);\n const response = ref(initial);\n\n ApiEndpointInitialization(api, state, response, initial);\n\n const execute = async (id: string) => {\n if (\n !api.value ||\n state.value === RequestState.Uninitialized ||\n // course already loaded successfully, don't load again\n (state.value === RequestState.Success && response.value?.id === id)\n ) {\n return;\n }\n\n try {\n response.value = initial;\n state.value = RequestState.Loading;\n response.value = await api.value.getCourse({ id });\n state.value = RequestState.Success;\n } catch {\n state.value = RequestState.Error;\n }\n };\n\n return {\n initial,\n state,\n response,\n execute\n };\n});\n\nexport interface ListCoursesInput {\n q?: string;\n page?: number;\n limit?: number;\n}\n\nexport interface ListCoursesResponseCourse extends HellewiCoursePartial {\n participantcount?: HellewiParticipantCount;\n}\n\nexport interface ListCoursesResponse {\n count: number;\n courses: ListCoursesResponseCourse[];\n locations: HellewiLocation[];\n}\n\nexport const useListCourses: ApiEndpoint<\n ListCoursesInput,\n ListCoursesResponse\n> = memoize(() => {\n const initial: ListCoursesResponse = { count: 0, courses: [], locations: [] };\n const { api } = useCourseApi();\n const state = ref(RequestState.Uninitialized);\n const response = ref(initial);\n const currentParams = ref(undefined);\n const ongoing = ref | undefined>(undefined);\n\n ApiEndpointInitialization(api, state, response, initial);\n\n const execute = async (params: ListCoursesInput) => {\n if (\n !api.value ||\n state.value === RequestState.Uninitialized ||\n // don't load again if this is already successfully loaded\n (state.value === RequestState.Success &&\n isEqual(currentParams.value, params))\n ) {\n return;\n } else if (ongoing.value) {\n // cancel the previous ongoing load\n ongoing.value.cancel();\n }\n\n ongoing.value = new PCancelable(async (resolve, reject, onCancel) => {\n onCancel(() => reject('cancelled'));\n try {\n if (!api.value) {\n return;\n }\n const responseRaw = await api.value.listCoursesRaw(params);\n const partialCourses = await responseRaw.value();\n const ids = partialCourses.map((course) => course.id);\n const participantCounts = isEmpty(ids)\n ? []\n : await api.value.listCourseParticipantCounts({\n ids\n });\n\n const count = Math.min(\n 9996, // Upper limit of the API is currently 10k, limit to full pages\n parseInt(responseRaw.raw.headers.get('x-total-count') as string, 10)\n );\n const locations: HellewiLocation[] = filterUndefineds(\n map((course) => course.location, partialCourses)\n );\n const courses = map(\n (course) => ({\n ...course,\n participantcount: find(\n (pc) => pc.id === course.id,\n participantCounts\n )\n }),\n partialCourses\n );\n\n resolve({ count, courses, locations });\n } catch {\n reject();\n }\n });\n\n try {\n state.value = RequestState.Loading;\n response.value = initial;\n response.value = await ongoing.value;\n currentParams.value = params;\n state.value = RequestState.Success;\n } catch (err) {\n if (err !== 'cancelled') {\n state.value = RequestState.Error;\n }\n // if this request was cancelled, don't touch the request state as the cancelling\n // request will handle the situation\n }\n ongoing.value = undefined;\n };\n\n return {\n initial,\n state,\n response,\n execute\n };\n});\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('b-navbar',{staticClass:\"nav-container\"},[_c('template',{slot:\"brand\"},[_c('Logo')],1),_c('template',{slot:\"end\"},[_c('b-navbar-item',{attrs:{\"tag\":\"router-link\",\"to\":{\n path: (\"/\" + _vm.language + \"/search\")\n }}},[_vm._v(\" \"+_vm._s(_vm.$t('header.browse')))]),_c('b-navbar-item',{attrs:{\"tag\":\"router-link\",\"to\":{ path: (\"/\" + _vm.language + \"/service-providers\") }}},[_vm._v(\" \"+_vm._s(_vm.$t('header.serviceProviders'))+\" \")]),_c('LanguageSelection')],1)],2)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('b-navbar-dropdown',{attrs:{\"right\":\"\",\"collapsible\":\"\"}},[_c('template',{slot:\"label\"},[_c('div',{staticClass:\"language-columns\"},[_c('b-icon',{attrs:{\"icon\":\"earth\"}}),_c('span',{staticClass:\"mobile\"},[_vm._v(_vm._s(_vm.$t('header.languages')))])],1)]),_c('b-navbar-item',{on:{\"click\":function($event){return _vm.changeLanguage('fi')}}},[_vm._v(\" Suomeksi \")]),_c('b-navbar-item',{on:{\"click\":function($event){return _vm.changeLanguage('sv')}}},[_vm._v(\" På svenska \")]),_c('b-navbar-item',{on:{\"click\":function($event){return _vm.changeLanguage('en')}}},[_vm._v(\" In English \")])],2)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./language-selection.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!./language-selection.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./language-selection.vue?vue&type=template&id=627ea928&scoped=true\"\nimport script from \"./language-selection.vue?vue&type=script&lang=ts\"\nexport * from \"./language-selection.vue?vue&type=script&lang=ts\"\nimport style0 from \"./language-selection.vue?vue&type=style&index=0&id=627ea928&prod&lang=scss&scoped=true\"\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 \"627ea928\",\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('b-navbar-item',{staticClass:\"logo-link\",attrs:{\"tag\":\"router-link\",\"to\":{ path: '/' + _vm.language },\"aria-label\":_vm.$t('logo.frontPage')}},[(_vm.serviceName !== 'E-opisto.fi')?_c('img',{staticClass:\"logo-image\",style:('maxWidth: ' + _vm.width),attrs:{\"src\":require(\"../../../frontend-assets/logo.svg\"),\"alt\":\"Linnunrata.fi\"}}):_vm._e(),(_vm.serviceName === 'E-opisto.fi')?_c('img',{staticClass:\"logo-image\",style:('maxWidth: ' + _vm.width + '; maxHeight: 100%'),attrs:{\"src\":require(\"../../../frontend-assets/logo.jpg\"),\"alt\":\"Linnunrata.fi\"}}):_vm._e()])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./logo.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!./logo.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./logo.vue?vue&type=template&id=4e8e138e&scoped=true&%3Aclass=%7B%20eopisto%3A%20serviceName%20%3D%3D%3D%20'E-opisto.fi'%20%7D\"\nimport script from \"./logo.vue?vue&type=script&lang=ts\"\nexport * from \"./logo.vue?vue&type=script&lang=ts\"\nimport style0 from \"./logo.vue?vue&type=style&index=0&id=4e8e138e&prod&lang=scss&scoped=true\"\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 \"4e8e138e\",\n null\n \n)\n\nexport default component.exports","\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!./header.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!./header.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./header.vue?vue&type=template&id=4311976c&scoped=true\"\nimport script from \"./header.vue?vue&type=script&lang=ts\"\nexport * from \"./header.vue?vue&type=script&lang=ts\"\nimport style0 from \"./header.vue?vue&type=style&index=0&id=4311976c&prod&scoped=true&lang=css\"\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 \"4311976c\",\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('nav',{staticClass:\"header-mobile\"},[_c('b-button',{staticClass:\"back-button\",attrs:{\"rounded\":\"\"},on:{\"click\":_vm.goBack}},[_c('b-icon',{staticClass:\"side-icon\",attrs:{\"icon\":\"arrow-left\",\"size\":\"is-medium\"}})],1),_c('Logo',{attrs:{\"width\":_vm.logoWidth}}),_c('b-button',{staticClass:\"menu-button\",attrs:{\"rounded\":\"\"},on:{\"click\":function($event){_vm.menuModalActive = true}}},[_c('b-icon',{staticClass:\"side-icon\",attrs:{\"icon\":\"menu\",\"size\":\"is-medium\"}})],1),_c('b-modal',{attrs:{\"width\":640,\"scroll\":\"keep\"},model:{value:(_vm.menuModalActive),callback:function ($$v) {_vm.menuModalActive=$$v},expression:\"menuModalActive\"}},[_c('div',{staticClass:\"content notification\"},[_c('b-navbar-item',{attrs:{\"tag\":\"router-link\",\"to\":{ path: (\"/\" + _vm.language + \"/search\") }}},[_vm._v(\" \"+_vm._s(_vm.$t('header.browse')))]),_c('b-navbar-item',{attrs:{\"tag\":\"router-link\",\"to\":{ path: (\"/\" + _vm.language + \"/service-providers\") }}},[_vm._v(\" \"+_vm._s(_vm.$t('header.serviceProviders'))+\" \")]),_c('LanguageSelection')],1)])],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./header-mobile.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!./header-mobile.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./header-mobile.vue?vue&type=template&id=7cbfb93d&scoped=true\"\nimport script from \"./header-mobile.vue?vue&type=script&lang=ts\"\nexport * from \"./header-mobile.vue?vue&type=script&lang=ts\"\nimport style0 from \"./header-mobile.vue?vue&type=style&index=0&id=7cbfb93d&prod&lang=scss&scoped=true\"\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 \"7cbfb93d\",\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('footer',{staticClass:\"footer\"},[_c('div',{staticClass:\"container\"},[_c('div',{staticClass:\"columns is-centered\"},[_c('div',{staticClass:\"column is-two-fifths\"},[_c('div',{staticClass:\"content\"},[_c('h3',{staticClass:\"has-text-weight-light\"},[_vm._v(\" \"+_vm._s(_vm.$tc('footer.amountOfCourses', _vm.totalCourseCount, { n: _vm.totalCourseCount === 0 ? _vm.$t('footer.many') : _vm.totalCourseCount }))+\" \")])])]),_c('div',{staticClass:\"column\"}),_c('div',{staticClass:\"column\"},[_c('nav',{staticClass:\"menu\"},[_c('p',{staticClass:\"menu-label\"},[_vm._v(\" \"+_vm._s(_vm.$t('footer.languages'))+\" \")]),_c('ul',{staticClass:\"menu-list\"},[_c('li',[_c('a',{on:{\"click\":function($event){return _vm.changeLanguage('fi')}}},[_vm._v(\"Suomeksi\")])]),_c('li',[_c('a',{on:{\"click\":function($event){return _vm.changeLanguage('sv')}}},[_vm._v(\"På svenska\")])]),_c('li',[_c('a',{on:{\"click\":function($event){return _vm.changeLanguage('en')}}},[_vm._v(\"In English\")])])])])]),_c('div',{staticClass:\"column\"},[_c('nav',{staticClass:\"menu\"},[_c('p',{staticClass:\"menu-label\"},[_vm._v(_vm._s(_vm.$t('footer.serviceName')))]),_c('ul',{staticClass:\"menu-list\"},[_c('li',[_c('router-link',{attrs:{\"to\":{ path: (\"/\" + _vm.language + \"/search\") }}},[_vm._v(_vm._s(_vm.$t('footer.browse')))])],1),_c('li',[_c('router-link',{attrs:{\"to\":{ path: (\"/\" + _vm.language + \"/service-providers\") }}},[_vm._v(_vm._s(_vm.$t('footer.serviceProviders')))])],1),(false)?_c('li',[_c('router-link',{attrs:{\"to\":{ path: (\"/\" + _vm.language) }}},[_vm._v(_vm._s(_vm.$t('footer.howTo')))])],1):_vm._e()])])])]),_c('div',{staticClass:\"content has-text-centered mt-6\"},[_c('p',[_vm._v(_vm._s(_vm.$t('footer.poweredBy')))])])])])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./footer.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!./footer.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./footer.vue?vue&type=template&id=372c9a6f\"\nimport script from \"./footer.vue?vue&type=script&lang=ts\"\nexport * from \"./footer.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 (_vm.center)?_c('l-map',{attrs:{\"zoom\":14,\"center\":_vm.center,\"options\":_vm.MAP_OPTIONS}},[_c('l-control-zoom'),_c('l-tile-layer',{attrs:{\"url\":_vm.URL}}),_c('l-marker',{attrs:{\"lat-lng\":_vm.center,\"icon\":_vm.markerIcon}},[_c('l-tooltip',[_vm._v(_vm._s(_vm.text))])],1)],1):_vm._e()}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./course-map.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!./course-map.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./course-map.vue?vue&type=template&id=ae706af8\"\nimport script from \"./course-map.vue?vue&type=script&lang=ts\"\nexport * from \"./course-map.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',[(_vm.price)?_c('span',{staticClass:\"price\"},[_vm._v(\" \"+_vm._s(_vm._f(\"price\")(_vm.price))+\" \")]):_c('span',{staticClass:\"price\"},[_vm._v(_vm._s(_vm.$t('registrationBox.noprice')))]),(_vm.course.begins && _vm.course.ends)?_c('span',[_c('b-icon',{staticClass:\"icon\",attrs:{\"icon\":\"calendar-today\",\"size\":\"is-small\"}}),_vm._v(\" \"+_vm._s(_vm._f(\"dateRange\")(_vm.course.begins,_vm.course.ends))+\" \")],1):_vm._e(),_c('div',{staticClass:\"weekdays\"},[_c('b-icon',{staticClass:\"icon left-margin weekday-icon\",attrs:{\"icon\":\"calendar-clock\",\"size\":\"is-small\"}}),_c('div',_vm._l((_vm.sortBy('weekday', _vm.formattedWeekdays)),function(day){return _c('div',{key:String(day.weekday),staticClass:\"weekday\"},[(day.weekday)?_c('span',{staticClass:\"weekday-short\"},[_vm._v(\" \"+_vm._s(_vm.$d(day.weekday, 'weekdayShort'))+\" \")]):_vm._e(),(day.times.length === 1)?_c('span',[_vm._v(\" \"+_vm._s(day.times[0].begins)+\"–\"+_vm._s(day.times[0].ends)+\" \")]):_vm._e(),(day.times.length > 1)?_c('span',[_c('b-collapse',{attrs:{\"open\":false,\"position\":\"is-bottom\",\"aria-id\":\"weekdays\"},scopedSlots:_vm._u([{key:\"trigger\",fn:function(props){return [_c('a',{staticClass:\"is-primary weekday-times\",attrs:{\"aria-controls\":\"weekdays\"}},[_vm._v(\" \"+_vm._s(props.open ? _vm.$t('registrationBox.hidetimes') : _vm.$t('registrationBox.severaltimes'))+\" \"),_c('b-icon',{staticClass:\"is-primary\",attrs:{\"icon\":props.open ? 'menu-up' : 'menu-down'}})],1)]}}],null,true)},_vm._l((day.times),function(time){return _c('p',{key:time.begins + time.ends},[_vm._v(\" \"+_vm._s(time.begins)+\"–\"+_vm._s(time.ends)+\" \")])}),0)],1):_vm._e()])}),0)],1),_c('b',[_vm._v(\" \"+_vm._s(_vm.$t('registrationBox.availablePlaces'))+\" \")]),_c('div',{staticClass:\"availability-container\"},[_c('div',{staticClass:\"availability\",class:(\"type--\" + _vm.availability)}),(_vm.availability)?_c('span',[_vm._v(\" \"+_vm._s(_vm.$t((\"registrationBox.\" + _vm.availability)))+\" \")]):_vm._e()]),(_vm.course.registrationbegins)?_c('span',{staticClass:\"info-section\"},[_c('b',[_vm._v(_vm._s(_vm.$t('registrationBox.registrationPeriodStarts')))]),_c('br'),_vm._v(\" \"+_vm._s(_vm._f(\"dateTime\")(_vm.course.registrationbegins))+\" \")]):_vm._e(),(_vm.course.registrationendssoft)?_c('span',{staticClass:\"info-section\"},[_c('b',[_vm._v(_vm._s(_vm.$t('registrationBox.registrationPeriodEnds')))]),_c('br'),_vm._v(\" \"+_vm._s(_vm._f(\"midnight\")(_vm.course.registrationendssoft))+\" \")]):_vm._e(),(!_vm.course.registrationbegins && !_vm.course.registrationendssoft)?_c('span',{staticClass:\"info-section\"},[_c('b',[_vm._v(_vm._s(_vm.$t('registrationBox.registrationPeriod')))]),_c('br'),_vm._v(\" \"+_vm._s(_vm.$t('registrationBox.notprovided'))+\" \")]):_vm._e(),_c('b-button',{staticClass:\"is-primary button\",attrs:{\"tag\":\"a\",\"href\":_vm.course.registrationlink,\"target\":\"_blank\",\"disabled\":!_vm.course.participantcount.registrationopen}},[_vm._v(\" \"+_vm._s(_vm.$t('registrationBox.register'))+\" \")])],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import { HellewiParticipantCount } from '../api';\n\nexport enum Availability {\n sparesAvailable = 'sparesAvailable',\n full = 'full',\n almostfull = 'almostfull',\n available = 'available',\n registrationClosed = 'registrationClosed'\n}\nexport const getAvailability = (\n pc: HellewiParticipantCount | undefined\n): Availability | undefined => {\n if (!pc) {\n return undefined;\n }\n if (!pc.registrationopen) {\n return Availability.registrationClosed;\n } else if (pc.full && pc.sparefull) {\n return Availability.full;\n } else if (pc.full && !pc.sparefull) {\n return Availability.sparesAvailable;\n } else if (pc.almostfull && !pc.full) {\n return Availability.almostfull;\n } else if (!pc.almostfull && !pc.full) {\n return Availability.available;\n }\n return undefined;\n};\n","import { find } from 'lodash/fp';\n\nimport { HellewiCoursePartial, HellewiCoursePrice } from '../api';\n\nexport const getDefaultPrice = (\n course: Pick | undefined\n): HellewiCoursePrice | undefined => {\n if (!course || !course.prices) {\n return undefined;\n }\n\n return find({ _default: true }, course.prices);\n};\n\nexport const getPriceEuros = (\n price: Pick | undefined\n): number | undefined => {\n if (price != null && price.amount != null) {\n return price.amount / 100;\n } else {\n return undefined;\n }\n};\n","import { setISODay } from 'date-fns';\nimport { groupBy, map, sortBy, values } from 'lodash/fp';\n\nimport { HellewiCourseDay } from '../api';\n\nexport interface FormatedWeekday {\n weekday: Date | undefined;\n times: WeekdayTime[];\n}\n\nexport interface WeekdayTime {\n begins: string | undefined;\n ends: string | undefined;\n}\n\nexport const currentYear = new Date().getFullYear();\nexport const nextYear = currentYear + 1;\nexport const currentMonth = new Date().getMonth() + 1;\n\nexport const WEEKDAY_VALUES = new Map([\n ['1', 'monday'],\n ['2', 'tuesday'],\n ['3', 'wednesday'],\n ['4', 'thursday'],\n ['5', 'friday'],\n ['6', 'saturday'],\n ['7', 'sunday']\n]);\n\n/**\n * Combine an array of HellewiCourseDays with possible multiple times on a same day\n * to an array that has only one entry for each day, and that day's times in a\n * separate array.\n *\n * Weekday is also converted to a javascript date so that it can be formatted\n * with i18n. (date and time are faked with setISODay, so use only the weekday from that)\n *\n * Grouped days are not sorted as it would be difficult to get sunday last.\n * Rely on backed giving the days sorted correctly and groupBy retaining that order.\n *\n * @param days array of HellewiCourseDays to be combined\n * @returns combined weekdays with possibly lots of times on a single weekday\n */\nexport const formatWeekdays = (\n days: HellewiCourseDay[] | undefined\n): FormatedWeekday[] =>\n map(\n (groupedDays) => ({\n weekday: groupedDays[0].weekday\n ? setISODay(new Date(), groupedDays[0].weekday)\n : undefined,\n times: sortBy(\n ({ begins }) => begins,\n map(({ begins, ends }) => ({ begins, ends }), groupedDays)\n )\n }),\n values(groupBy((day) => day.weekday, days))\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!./registration-box.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!./registration-box.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./registration-box.vue?vue&type=template&id=085355a3&scoped=true\"\nimport script from \"./registration-box.vue?vue&type=script&lang=ts\"\nexport * from \"./registration-box.vue?vue&type=script&lang=ts\"\nimport style0 from \"./registration-box.vue?vue&type=style&index=0&id=085355a3&prod&lang=scss&scoped=true\"\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 \"085355a3\",\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('b-collapse',{staticClass:\"card collapse-card\",attrs:{\"animation\":\"slide\",\"aria-id\":_vm.lessons.name + _vm.lessons.begins,\"open\":false},scopedSlots:_vm._u([{key:\"trigger\",fn:function(props){return _c('div',{staticClass:\"card-header collapse-card-header\",attrs:{\"role\":\"button\",\"aria-controls\":_vm.lessons.name + _vm.lessons.begins}},[_c('span',{staticClass:\"card-header-title collapse-title-container\"},[(_vm.lessons.name)?_c('span',[_vm._v(_vm._s(_vm.lessons.name + ' '))]):_vm._e(),_c('div',{staticClass:\"collapse-title-details\"},[(_vm.lessons.begins && _vm.lessons.ends)?_c('div',{staticClass:\"collapse-title-detail\"},[_c('b-icon',{staticClass:\"icon collapse-title-icon\",attrs:{\"icon\":\"calendar-today\",\"size\":\"is-small\"}}),_c('p',[_vm._v(_vm._s(_vm._f(\"dateRange\")(_vm.lessons.begins,_vm.lessons.ends)))])],1):_vm._e(),(_vm.lessons.lessoncount)?_c('div',{staticClass:\"collapse-title-detail\"},[_c('b-icon',{staticClass:\"icon collapse-title-icon\",attrs:{\"icon\":\"timer-sand\",\"size\":\"is-small\"}}),_c('p',[_vm._v(\" \"+_vm._s(_vm.$tc('lessonsCollapse.lessons', _vm.lessons.lessoncount))+\" \")])],1):_vm._e()])]),_c('a',{staticClass:\"card-header-icon\"},[_c('b-icon',{attrs:{\"icon\":props.open ? 'chevron-up' : 'chevron-down'}})],1)])}}])},[_c('div',{staticClass:\"card-content\"},[_c('div',{staticClass:\"content\"},[(!_vm.lessons.lessons)?_c('span',[_vm._v(\" \"+_vm._s(_vm.$t('lessonsCollapse.lessonsNotprovided'))+\" \")]):_vm._e(),(_vm.lessons.lessons)?_c('div',{staticClass:\"lessons-table\"},[_c('b-table',{attrs:{\"data\":_vm.lessons.lessons,\"mobile-cards\":true}},[_c('b-table-column',{attrs:{\"custom-key\":\"day\"},scopedSlots:_vm._u([{key:\"default\",fn:function(props){return [_c('span',{staticClass:\"weekdayLong\"},[_vm._v(\" \"+_vm._s(_vm.$d(new Date(props.row.begins), 'weekdayLong'))+\" \"+_vm._s(_vm._f(\"dateRange\")(new Date(props.row.begins),new Date(props.row.ends)))+\" \")])]}}],null,false,461554443)}),_c('b-table-column',{attrs:{\"custom-key\":\"time\"},scopedSlots:_vm._u([{key:\"default\",fn:function(props){return [_vm._v(\" \"+_vm._s(_vm._f(\"timeRange\")(new Date(props.row.begins),new Date(props.row.ends)))+\" \")]}}],null,false,1019148718)}),_c('b-table-column',{attrs:{\"custom-key\":\"place\"},scopedSlots:_vm._u([{key:\"default\",fn:function(props){return [(props.row.location)?_c('span',[_vm._v(\" \"+_vm._s([props.row.location.name, props.row.location.address] .filter(Boolean) .join(', '))+\" \")]):_c('span',[_vm._v(\" \"+_vm._s(_vm.$t('lessonsCollapse.placenotprovided'))+\" \")])]}}],null,false,3619176102)})],1)],1):_vm._e()])])])}\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!./lessons-collapse.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!./lessons-collapse.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./lessons-collapse.vue?vue&type=template&id=fe20bad2&scoped=true\"\nimport script from \"./lessons-collapse.vue?vue&type=script&lang=ts\"\nexport * from \"./lessons-collapse.vue?vue&type=script&lang=ts\"\nimport style0 from \"./lessons-collapse.vue?vue&type=style&index=0&id=fe20bad2&prod&lang=scss&scoped=true\"\nimport style1 from \"./lessons-collapse.vue?vue&type=style&index=1&id=fe20bad2&prod&lang=scss\"\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 \"fe20bad2\",\n null\n \n)\n\nexport default component.exports","\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!./course.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!./course.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./course.vue?vue&type=template&id=0a0045fb&scoped=true\"\nimport script from \"./course.vue?vue&type=script&lang=ts\"\nexport * from \"./course.vue?vue&type=script&lang=ts\"\nimport style0 from \"./course.vue?vue&type=style&index=0&id=0a0045fb&prod&lang=scss&scoped=true\"\nimport style1 from \"./course.vue?vue&type=style&index=1&id=0a0045fb&prod&lang=scss\"\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 \"0a0045fb\",\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'),_c('section',{staticClass:\"section content--full-height\"},[_c('h1',{staticClass:\"title has-text-weight-light headline\"},[_vm._v(\" \"+_vm._s(_vm.$t('index.title'))+\" \")]),_c('LanderSearch',{on:{\"locating-error\":_vm.onLocatingError,\"locating-successful\":_vm.onLocatingSuccessful}})],1),_c('section',[_c('Categories',{attrs:{\"classifications\":_vm.popularClassifications}})],1),_c('Footer')],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import { ref } from '@vue/composition-api';\nimport { isEqual, memoize } from 'lodash/fp';\nimport PCancelable from 'p-cancelable';\n\nimport {\n Configuration,\n CatalogApi,\n CatalogApiInterface,\n HellewiCatalog\n} from '../api';\n\nimport {\n Api,\n ApiEndpoint,\n ApiEndpointInitialization,\n RequestState\n} from '../utils/api-utils';\n\n/**\n * Use catalog API\n */\nexport const useCatalogApi: Api = memoize(() => {\n const api = ref(undefined);\n\n const changeConfiguration = (configuration: Configuration) => {\n api.value = new CatalogApi(configuration);\n };\n\n return {\n api,\n changeConfiguration\n };\n});\n\nexport const useGetCatalogUnfiltered: ApiEndpoint<\n void,\n HellewiCatalog | undefined\n> = memoize(() => {\n const initial = undefined;\n const { api } = useCatalogApi();\n const state = ref(RequestState.Uninitialized);\n const response = ref(initial);\n\n ApiEndpointInitialization(api, state, response, initial);\n\n const execute = async () => {\n if (\n !api.value ||\n state.value === RequestState.Uninitialized ||\n // request already ongoing, don't start a new one\n state.value === RequestState.Loading ||\n // don't load again if this is already successfully loaded\n state.value === RequestState.Success\n ) {\n return;\n }\n\n try {\n state.value = RequestState.Loading;\n response.value = await api.value.getCatalog({});\n state.value = RequestState.Success;\n } catch {\n response.value = initial;\n state.value = RequestState.Error;\n }\n };\n\n return {\n initial,\n state,\n response,\n execute\n };\n});\n\nexport const useGetCatalog: ApiEndpoint<\n string | undefined,\n HellewiCatalog | undefined\n> = memoize(() => {\n const initial = undefined;\n const { api } = useCatalogApi();\n const state = ref(RequestState.Uninitialized);\n const response = ref(initial);\n const currentQ = ref(undefined);\n const ongoing = ref | undefined>(\n undefined\n );\n\n ApiEndpointInitialization(api, state, response, initial);\n\n const execute = async (q: string | undefined) => {\n if (\n !api.value ||\n state.value === RequestState.Uninitialized ||\n // don't load again if this is already successfully loaded\n (state.value === RequestState.Success && isEqual(currentQ.value, q))\n ) {\n return;\n } else if (ongoing.value) {\n // cancel the previous ongoing load\n ongoing.value.cancel();\n }\n\n ongoing.value = new PCancelable(async (resolve, reject, onCancel) => {\n onCancel(() => reject('cancelled'));\n try {\n if (!api.value) {\n return;\n }\n const catalog = await api.value.getCatalog({ q });\n resolve(catalog);\n } catch {\n reject();\n }\n });\n\n try {\n state.value = RequestState.Loading;\n response.value = initial;\n response.value = await ongoing.value;\n currentQ.value = q;\n state.value = RequestState.Success;\n } catch (err) {\n if (err !== 'cancelled') {\n state.value = RequestState.Error;\n }\n // if this request was cancelled, don't touch the request state as the cancelling\n // request will handle the situation\n }\n ongoing.value = undefined;\n };\n\n return {\n initial,\n state,\n response,\n execute\n };\n});\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('section',[_c('div',{staticClass:\"container\"},[_c('b-field',{staticClass:\"lines-container\",attrs:{\"position\":\"is-centered\",\"grouped\":\"\",\"group-multiline\":\"\"}},[_c('b-field',{staticClass:\"field-container\",attrs:{\"label\":_vm.$t('landerSearch.keyword')}},[_c('b-autocomplete',{ref:\"keywordElement\",staticClass:\"word-search\",attrs:{\"placeholder\":_vm.$t('landerSearch.searchForCourse'),\"type\":\"is-primary\",\"icon-right\":\"magnify\",\"clearable\":\"\",\"data\":_vm.searchSuggestions,\"open-on-focus\":true},scopedSlots:_vm._u([{key:\"header\",fn:function(){return [(_vm.searchSuggestions.length > 0)?_c('strong',[_vm._v(_vm._s(_vm.$t('landerSearch.commonSearches')))]):_vm._e()]},proxy:true}]),model:{value:(_vm.keyword),callback:function ($$v) {_vm.keyword=$$v},expression:\"keyword\"}})],1),_c('b-field',{staticClass:\"field-container location-search\"},[_c('template',{slot:\"label\"},[_vm._v(\" \"+_vm._s(_vm.$t('landerSearch.location'))+\" \"),_c('a',{staticClass:\"has-text-weight-medium\",on:{\"click\":_vm.getMyLocation}},[_vm._v(_vm._s(_vm.$t('landerSearch.useMyCurrentLocation')))])]),_c('b-autocomplete',{attrs:{\"placeholder\":_vm.$t('landerSearch.address'),\"type\":\"search\",\"data\":_vm.locationSuggestions,\"icon-right\":\"map-marker-outline\",\"clearable\":\"\"},on:{\"select\":_vm.onLocationAutocompleteSelect},model:{value:(_vm.location),callback:function ($$v) {_vm.location=$$v},expression:\"location\"}})],2),_c('b-field',{staticClass:\"field-container\",attrs:{\"grouped\":\"\"}},[_c('b-field',{attrs:{\"label\":_vm.$t('landerSearch.distance'),\"expanded\":\"\"}},[_c('b-dropdown',{model:{value:(_vm.distance),callback:function ($$v) {_vm.distance=$$v},expression:\"distance\"}},[_c('b-input',{staticClass:\"distance-search\",attrs:{\"slot\":\"trigger\",\"disabled\":_vm.location === undefined || _vm.location === '',\"type\":\"button\",\"icon-right\":\"arrow-expand\",\"value\":_vm.location ? _vm.distance + ' km' : _vm.$t('landerSearch.distance')},slot:\"trigger\"}),_c('b-dropdown-item',{attrs:{\"value\":10,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"10 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":25,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"25 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":50,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"50 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":100,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"100 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":250,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"250 km\")])])],1)],1),_c('b-field',[_c('b-button',{staticClass:\"is-uppercase search-button\",attrs:{\"type\":\"is-primary\"},on:{\"click\":_vm.search}},[_vm._v(_vm._s(_vm.$t('landerSearch.search')))])],1)],1)],1),_c('b-loading',{attrs:{\"is-full-page\":false,\"can-cancel\":true},model:{value:(_vm.locationLoading),callback:function ($$v) {_vm.locationLoading=$$v},expression:\"locationLoading\"}}),_c('p',{staticClass:\"note\"},[_c('b-icon',{attrs:{\"icon\":\"lightbulb-on-outline\"}}),_vm._v(\" \"+_vm._s(_vm.$t('landerSearch.onlineClasses'))+\" \")],1)],1)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import { filter, isEmpty } from 'lodash/fp';\n\nimport { Geopoint } from '../api';\nimport municipalitiesData from '../../frontend-assets/kunnat.json';\n\nconst municipalities = municipalitiesData.map(\n (m) => `${m.Kunta}, ${m.Maakunta}`\n);\n\nconst OPENSTREETMAP_NOMINATIM_BASEURL = 'https://nominatim.openstreetmap.org';\n\nexport const DEFAULT_ZOOM = 5;\nexport const DEFAULT_GEOPOINT: Geopoint = { lat: 65.3, lon: 26.770566 };\nexport const DISTANCE_AND_ZOOM_PAIRS = new Map([\n [undefined, DEFAULT_ZOOM],\n [10, 12],\n [25, 10],\n [50, 9],\n [100, 7.5],\n [250, 6]\n]);\n\nexport interface Address {\n county: string;\n city: string;\n}\n\n/**\n * Get address for coordinates from openstreetmap nominatim service\n *\n * @param geoPoint coordinates to be translated to address\n * @returns\n */\nexport const getAddressByCoordinates = async (\n geoPoint: Geopoint\n): Promise
=> {\n const query = new URLSearchParams({\n lat: String(geoPoint.lat),\n lon: String(geoPoint.lon),\n format: 'json'\n });\n\n const response = await fetch(\n `${OPENSTREETMAP_NOMINATIM_BASEURL}/reverse?${query.toString()}`\n );\n if (!response.ok) {\n return undefined;\n }\n\n const data = await response.json();\n if (\n !data.address.county ||\n isEmpty(data.address.county) ||\n !data.address.city ||\n isEmpty(data.address.city)\n ) {\n return undefined;\n }\n\n return {\n county: data.address.county,\n city: data.address.city\n };\n};\n\n/**\n * Get coordinates for address from openstreetmap nominatim service\n *\n * @param address\n * @returns GeoPoint if coordinates were found, undefined if not\n */\nexport const getCoordinatesByAddress = async (\n address: string\n): Promise => {\n const query = new URLSearchParams({\n q: `${address}, finland`,\n format: 'json'\n });\n\n const response = await fetch(\n `${OPENSTREETMAP_NOMINATIM_BASEURL}/search?${query.toString()}`\n );\n if (!response.ok) {\n return undefined;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data: any[] = await response.json();\n if (isEmpty(data) || data.length < 1) {\n return undefined;\n }\n\n const lat = parseFloat(data[0].lat);\n const lon = parseFloat(data[0].lon);\n\n if (isNaN(lat) || isNaN(lon)) {\n return undefined;\n }\n\n return { lat, lon };\n};\n\n/**\n * Get a list of municipalities that match given input\n *\n * For location autocomplete\n *\n * @param input typed input\n * @returns array of municipality names\n */\nexport const getLocationSuggestions = (input: string | undefined): string[] => {\n if (!input || isEmpty(input)) {\n return [];\n }\n\n return filter(\n (municipality) => municipality.toLowerCase().includes(input.toLowerCase()),\n municipalities\n );\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!./lander-search.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!./lander-search.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./lander-search.vue?vue&type=template&id=ac9edd0c&scoped=true\"\nimport script from \"./lander-search.vue?vue&type=script&lang=ts\"\nexport * from \"./lander-search.vue?vue&type=script&lang=ts\"\nimport style0 from \"./lander-search.vue?vue&type=style&index=0&id=ac9edd0c&prod&scoped=true&lang=css\"\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 \"ac9edd0c\",\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('section',{class:{ eopisto: _vm.serviceName === 'E-opisto.fi' }},[_c('div',{staticClass:\"imagecontainer\"},[(_vm.serviceName !== 'E-opisto.fi')?_c('img',{staticClass:\"image\",attrs:{\"src\":require(\"../../frontend-assets/frontpage.svg\"),\"alt\":\"\"}}):_vm._e(),(_vm.serviceName === 'E-opisto.fi')?_c('img',{staticClass:\"image\",attrs:{\"src\":require(\"../../frontend-assets/frontpage.jpg\"),\"alt\":\"\"}}):_vm._e()]),_c('div',{staticClass:\"content\"},[_c('div',{staticClass:\"title has-text-weight-light\"},[_vm._v(\" \"+_vm._s(_vm.$t('landerCategories.popularCategories'))+\" \")]),(_vm.classifications)?_c('b-taglist',{staticClass:\"tags-container\"},_vm._l((_vm.classifications),function(classification){return _c('div',{key:classification.id,staticClass:\"tag rounded is-medium\"},[_c('router-link',{staticClass:\"category-link\",attrs:{\"to\":{\n path: (\"/\" + _vm.language + \"/search?classifications=\" + (classification.id))\n }}},[_vm._v(\" \"+_vm._s(classification.name)+\" \")])],1)}),0):_vm._e()],1)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./lander-categories.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!./lander-categories.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./lander-categories.vue?vue&type=template&id=36792a28&scoped=true\"\nimport script from \"./lander-categories.vue?vue&type=script&lang=ts\"\nexport * from \"./lander-categories.vue?vue&type=script&lang=ts\"\nimport style0 from \"./lander-categories.vue?vue&type=style&index=0&id=36792a28&prod&lang=scss&scoped=true\"\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 \"36792a28\",\n null\n \n)\n\nexport default component.exports","\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!./index.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!./index.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=0f61d96f&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=ts\"\nexport * from \"./index.vue?vue&type=script&lang=ts\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=0f61d96f&prod&scoped=true&lang=css\"\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 \"0f61d96f\",\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('router-view',{attrs:{\"apiConfiguration\":_vm.apiConfiguration}})}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import { ref } from '@vue/composition-api';\nimport { map, memoize } from 'lodash/fp';\n\nimport {\n Configuration,\n HellewiTenant,\n TenantApi,\n TenantApiInterface\n} from '../api';\n\nimport {\n Api,\n ApiEndpoint,\n ApiEndpointInitialization,\n RequestState\n} from '../utils/api-utils';\n\n/**\n * Use tenant API\n *\n * This is a singleton function that will return always the same\n * variable references that are returned on the first call.\n * (accomplished via memoize)\n */\nexport const useTenantApi: Api = memoize(() => {\n const api = ref(undefined);\n\n const changeConfiguration = (configuration: Configuration) => {\n api.value = new TenantApi(configuration);\n };\n\n return {\n api,\n changeConfiguration\n };\n});\n\nconst formatUrl = (url: string | undefined): string | undefined => {\n if (!url) {\n return undefined;\n } else if (url.includes('://')) {\n return url;\n } else {\n return `https://${url}`;\n }\n};\n\nexport const useListTenants: ApiEndpoint = memoize(\n () => {\n const initial: HellewiTenant[] = [];\n const { api } = useTenantApi();\n const state = ref(RequestState.Uninitialized);\n const response = ref(initial);\n\n ApiEndpointInitialization(api, state, response, initial);\n\n const execute = async () => {\n if (\n !api.value ||\n state.value === RequestState.Uninitialized ||\n state.value === RequestState.Loading ||\n // don't load again if this is already successfully loaded\n state.value === RequestState.Success\n ) {\n return;\n }\n\n try {\n state.value = RequestState.Loading;\n response.value = map(\n (tenant) => ({\n ...tenant,\n facebook: formatUrl(tenant.facebook),\n twitter: formatUrl(tenant.twitter),\n instagram: formatUrl(tenant.instagram),\n linkedin: formatUrl(tenant.linkedin),\n homepage: formatUrl(tenant.homepage)\n }),\n await api.value.listTenants()\n );\n state.value = RequestState.Success;\n } catch {\n response.value = initial;\n state.value = RequestState.Error;\n }\n };\n\n return {\n initial,\n state,\n response,\n execute\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!./language.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!./language.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./language.vue?vue&type=template&id=d479b7ac\"\nimport script from \"./language.vue?vue&type=script&lang=ts\"\nexport * from \"./language.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'),_c('div',{staticClass:\"notfound-container\"},[_c('div',{staticClass:\"content-container\"},[_c('h1',{staticClass:\"title\"},[_vm._v(_vm._s(_vm.$t('notFound.notFound')))]),_c('p',[_vm._v(_vm._s(_vm.$t('notFound.explanation')))]),_c('router-link',{attrs:{\"to\":{ path: '/' + _vm.language }}},[_vm._v(_vm._s(_vm.$t('notFound.goBack')))])],1),_c('img',{staticClass:\"image\",attrs:{\"src\":require(\"../../frontend-assets/404.png\"),\"alt\":\"Bird with sunglasses\"}})]),_c('Footer',{attrs:{\"apiConfiguration\":_vm.apiConfiguration}})],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./not-found.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!./not-found.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./not-found.vue?vue&type=template&id=6daa6884&scoped=true\"\nimport script from \"./not-found.vue?vue&type=script&lang=ts\"\nexport * from \"./not-found.vue?vue&type=script&lang=ts\"\nimport style0 from \"./not-found.vue?vue&type=style&index=0&id=6daa6884&prod&lang=scss&scoped=true\"\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 \"6daa6884\",\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',{class:{ eopisto: _vm.serviceName === 'E-opisto.fi' }},[_c('SearchHeaderDesktop',{staticClass:\"desktop-search\",attrs:{\"keyword\":_vm.keyword,\"location\":_vm.location,\"distance\":_vm.distance || undefined}}),_c('SearchHeaderMobile',{staticClass:\"mobile-search\",attrs:{\"keyword\":_vm.keyword,\"location\":_vm.location,\"distance\":_vm.distance || undefined}}),_c('main',{staticClass:\"columns search-content is-gapless\"},[_c('aside',{staticClass:\"cards-container aside-content\"},[_c('div',{staticClass:\"desktop-search\"},[_c('span',{staticClass:\"is-uppercase is-size-7\"},[_c('span',[_vm._v(\" \"+_vm._s(_vm.$tc(\"search.amountOfSearchResults\", _vm.courseCount, { n: _vm.courseCount > 9990 ? _vm.$t('search.over10000') : _vm.courseCount }))+\" \")]),(_vm.location && _vm.distance)?_c('span',[_vm._v(\" · \"+_vm._s(_vm.$tc('search.area', _vm.distance))+\" \")]):_vm._e()]),(_vm.location)?_c('h1',{staticClass:\"has-text-weight-light mt-0\"},[_vm._v(\" \"+_vm._s(_vm.$t('search.offeringInArea', { location: _vm.location }))+\" \")]):_vm._e()]),_c('SearchFilters',{staticClass:\"filter-container\",attrs:{\"catalog\":_vm.catalog,\"classifications\":_vm.classifications,\"distanceLearning\":_vm.distanceLearning,\"languages\":_vm.languages,\"semester\":_vm.semester,\"serviceProviders\":_vm.serviceProviders,\"weekdays\":_vm.weekdays}}),(_vm.serviceProviders)?_c('div',{staticClass:\"tenant-container\"},[_c('TenantDropdown',{staticClass:\"tenant\",attrs:{\"tenant\":_vm.tenant,\"browseLink\":false,\"detailsText\":true}})],1):_vm._e(),_c('span',{staticClass:\"is-uppercase is-size-7 mobile-total\"},[_vm._v(\" \"+_vm._s(_vm.$tc(\"search.amountOfSearchResults\", _vm.courseCount, { n: _vm.courseCount > 9990 ? _vm.$t('search.over10000') : _vm.courseCount }))+\" \")]),_c('b-button',{staticClass:\"show-map-button\",attrs:{\"rounded\":\"\"},on:{\"click\":function($event){_vm.showMap = !_vm.showMap}}},[_c('span',[_vm._v(_vm._s(_vm.$t('search.showMap')))])]),_c('CourseList',{attrs:{\"courses\":_vm.courses,\"isLoading\":_vm.isLoading}}),(_vm.courses.length > 0)?_c('div',{staticClass:\"pagination-container\"},[_c('SearchPagination',{attrs:{\"total\":_vm.courseCount,\"page\":_vm.page}})],1):_vm._e()],1),_c('section',{staticClass:\"column desktop-map\"},[_c('SearchMap',{attrs:{\"coordinates\":_vm.coordinates,\"zoom\":_vm.zoom,\"locations\":_vm.locations,\"courses\":_vm.courses,\"isLoading\":_vm.isLoading}})],1),_c('b-modal',{model:{value:(_vm.showMap),callback:function ($$v) {_vm.showMap=$$v},expression:\"showMap\"}},[_c('SearchMap',{key:_vm.showMap,staticClass:\"mobile-map\",attrs:{\"showMap\":_vm.showMap,\"coordinates\":_vm.coordinates,\"zoom\":_vm.zoom,\"locations\":_vm.locations,\"courses\":_vm.courses,\"isLoading\":_vm.isLoading}})],1)],1),_c('Footer')],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import { currentYear, nextYear } from './date-utils';\n\ninterface Params {\n keyword?: string | undefined;\n coords?:\n | {\n lat: number;\n lon: number;\n }\n | undefined;\n distance?: number | undefined;\n weekdays?: string[] | undefined;\n semester?: Semester | undefined;\n categories?: string[] | undefined;\n classifications?: string[] | undefined;\n serviceProviders?: string[] | undefined;\n distanceLearning?: string | undefined;\n}\n\nexport const generateQuery = (params: Params) => {\n const {\n keyword,\n coords,\n distance,\n weekdays,\n semester,\n classifications,\n serviceProviders,\n distanceLearning\n } = params;\n\n let query = '';\n if (keyword) {\n query = `${keyword} `;\n }\n if (distance && coords) {\n query += `distancefrom:${coords.lat},${coords.lon} distancesoft:<${distance}km distancehard:<${distance}km `;\n }\n\n if (weekdays) {\n for (const weekday of weekdays) {\n query += `weekday:${weekday} `;\n }\n }\n\n if (serviceProviders) {\n for (const serviceProvider of serviceProviders) {\n query += `tenant:${serviceProvider} `;\n }\n }\n\n if (classifications) {\n for (const classification of classifications) {\n query += `classification:${classification} `;\n }\n }\n\n if (semester) {\n query += `${dateRangeForSemester[semester]} `;\n }\n\n if (distanceLearning === 'true') {\n query += 'location:distancelearning ';\n } else if (distanceLearning === 'false') {\n query += 'location:!distancelearning ';\n }\n\n query = query.trimEnd();\n\n return query === '' ? undefined : query;\n};\n\nexport enum Semester {\n CurrentYearAutumn = 'currentYearAutumn',\n CurrentYearSpring = 'currentYearSpring',\n CurrentYearSummer = 'currentYearSummer',\n NextYearAutumn = 'nextYearAutumn',\n NextYearSpring = 'nextYearSpring',\n NextYearSummer = 'nextYearSummer'\n}\n\nexport enum DistanceLearning {\n True = 'true',\n False = 'false'\n}\n\n/**\n * Explanation in search-filters.vue where options are defined\n */\nconst dateRangeForSemester: { [key in Semester]: string } = {\n [Semester.CurrentYearAutumn]: `begins:>=${currentYear}-08-01 ends:<=${currentYear}-12-31`,\n [Semester.CurrentYearSpring]: `begins:>=${currentYear}-01-01 ends:<=${currentYear}-07-31`,\n [Semester.CurrentYearSummer]: `begins:>=${currentYear}-06-01 ends:<=${currentYear}-08-31`,\n [Semester.NextYearAutumn]: `begins:>=${nextYear}-08-01 ends:<=${nextYear}-12-31`,\n [Semester.NextYearSpring]: `begins:>=${nextYear}-01-01 ends:<=${nextYear}-07-31`,\n [Semester.NextYearSummer]: `begins:>=${nextYear}-06-01 ends:<=${nextYear}-08-31`\n};\n\nexport function isNumeric(value: string) {\n return /^\\d+$/.test(value);\n}\n","import { SetupContext, ref, watch } from '@vue/composition-api';\nimport { includes } from 'lodash/fp';\n\nimport { Geopoint } from '../api';\nimport { RequestState } from '../utils/api-utils';\nimport {\n DEFAULT_GEOPOINT,\n DEFAULT_ZOOM,\n DISTANCE_AND_ZOOM_PAIRS,\n getCoordinatesByAddress\n} from '../utils/location-utils';\nimport { generateQuery, isNumeric, Semester } from '../utils/query-utils';\n\nconst useSearch = (ctx: SetupContext) => {\n const geocodingState = ref(RequestState.Initialized);\n const coordinates = ref(DEFAULT_GEOPOINT);\n const zoom = ref(DEFAULT_ZOOM);\n const keyword = ref();\n const location = ref();\n const distance = ref();\n const weekdays = ref();\n const semester = ref();\n const classifications = ref();\n const languages = ref();\n const serviceProviders = ref();\n const distanceLearning = ref();\n const page = ref(1);\n const q = ref(undefined);\n\n watch(\n () => ctx.root.$route,\n async (route) => {\n page.value = isNumeric(route.query.page as string)\n ? parseInt(route.query.page as string, 10)\n : 1;\n\n keyword.value = route.query.q ? route.query.q.toString() : '';\n\n weekdays.value = route.query.weekdays\n ? (route.query.weekdays as string).split(',')\n : undefined;\n\n semester.value =\n route.query.semester && includes(route.query.semester, Semester)\n ? (route.query.semester as Semester)\n : undefined;\n\n classifications.value = route.query.classifications\n ? (route.query.classifications as string).split(',')\n : undefined;\n\n languages.value = route.query.languages\n ? (route.query.languages as string).split(',')\n : undefined;\n\n serviceProviders.value = route.query.serviceproviders\n ? (route.query.serviceproviders as string).split(',')\n : undefined;\n\n distanceLearning.value = route.query.distancelearning\n ? (route.query.distancelearning as string)\n : undefined;\n\n if (route.query.location) {\n geocodingState.value = RequestState.Loading;\n location.value = route.query.location.toString();\n try {\n const coords = await getCoordinatesByAddress(location.value);\n\n if (coords) {\n geocodingState.value = RequestState.Success;\n coordinates.value = { lat: coords.lat, lon: coords.lon };\n\n if (route.query.distance) {\n distance.value = Number(route.query.distance);\n zoom.value = route.query.distance\n ? DISTANCE_AND_ZOOM_PAIRS.get(Number(route.query.distance))\n : DEFAULT_ZOOM;\n }\n } else {\n geocodingState.value = RequestState.Error;\n }\n } catch (e) {\n geocodingState.value = RequestState.Error;\n }\n } else {\n geocodingState.value = RequestState.Initialized;\n location.value = undefined;\n distance.value = undefined;\n coordinates.value = DEFAULT_GEOPOINT;\n zoom.value = DEFAULT_ZOOM;\n }\n\n if (geocodingState.value !== RequestState.Error) {\n q.value = generateQuery({\n keyword: keyword.value,\n coords: location.value\n ? { lat: coordinates.value.lat, lon: coordinates.value.lon }\n : undefined,\n distance: distance.value,\n weekdays: weekdays.value,\n semester: semester.value,\n classifications: classifications.value,\n serviceProviders: serviceProviders.value,\n distanceLearning: distanceLearning.value\n });\n }\n },\n { immediate: true }\n );\n\n return {\n classifications,\n coordinates,\n distance,\n distanceLearning,\n geocodingState,\n keyword,\n languages,\n location,\n page,\n q,\n semester,\n serviceProviders,\n weekdays,\n zoom\n };\n};\n\nexport default useSearch;\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(!_vm.isLoading && !_vm.isEmpty(_vm.courses))?_c('div',{staticClass:\"cards\"},_vm._l((_vm.courses),function(course){return _c('CourseCard',{key:course.id,attrs:{\"course\":course,\"participantCount\":course.participantcount}})}),1):(!_vm.isLoading)?_c('div',{staticClass:\"noresults content\"},[_c('div',[_c('h4',[_vm._v(\" \"+_vm._s(_vm.$t('courseList.noResults'))+\" \")]),_c('p',[_vm._v(\" \"+_vm._s(_vm.$t('courseList.getMoreResults'))+\" \")])])]):_c('div',{staticClass:\"cards\"},[_c('CourseCard',{attrs:{\"isLoading\":\"\"}}),_c('CourseCard',{attrs:{\"isLoading\":\"\"}}),_c('CourseCard',{attrs:{\"isLoading\":\"\"}})],1)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"card\"},[(_vm.course)?_c('div',[_c('router-link',{attrs:{\"to\":{ path: _vm.getCourseLink(_vm.course.id) }}},[(_vm.getPriceEuros(_vm.getDefaultPrice(_vm.course)))?_c('div',{staticClass:\"price\"},[_vm._v(\" \"+_vm._s(_vm._f(\"price\")(_vm.getPriceEuros(_vm.getDefaultPrice(_vm.course))))+\" \")]):_vm._e(),(_vm.distanceLearning)?_c('b-icon',{staticClass:\"distancelearning\",attrs:{\"icon\":\"web\"}}):_vm._e(),_c('div',{staticClass:\"availability\",class:(\"type--\" + _vm.availability)},[_c('b-tooltip',{attrs:{\"type\":\"is-light\",\"label\":_vm.$t((\"courseCard.\" + _vm.availability))}},[_c('div',{staticClass:\"tooltip-placeholder\"})])],1),_c('div',{staticClass:\"card-image\",style:({ background: _vm.color })},[(_vm.serviceName !== 'E-opisto.fi')?_c('img',{staticClass:\"cover-image\",attrs:{\"src\":_vm.imageUrl,\"alt\":\"Cover image\"}}):_vm._e(),(_vm.serviceName === 'E-opisto.fi')?_c('img',{staticClass:\"cover-image\",style:({ objectFit: 'cover' }),attrs:{\"src\":_vm.imageUrl,\"alt\":\"Cover image\"}}):_vm._e()]),_c('div',{staticClass:\"card-content flex-column\"},[_c('p',{staticClass:\"title\"},[_c('v-clamp',{staticClass:\"title-v-clamp\",attrs:{\"expanded\":_vm.expanded,\"max-lines\":2},nativeOn:{\"mouseover\":function($event){_vm.expanded = true},\"mouseleave\":function($event){_vm.expanded = false}}},[_vm._v(_vm._s(_vm.decodedName))])],1),_c('div',{},[(_vm.course.location)?_c('p',{staticClass:\"info\"},[_c('b-icon',{staticClass:\"icon\",attrs:{\"icon\":\"map-marker\",\"size\":\"is-small\"}}),(_vm.course.location.city)?_c('span',[_vm._v(\" \"+_vm._s(_vm.course.location.city)+\", \")]):_vm._e(),_vm._v(\" \"+_vm._s(_vm.course.location.name)+\" \")],1):_vm._e(),_c('span',{staticClass:\"info\"},[_c('b-tooltip',{attrs:{\"type\":\"is-light\",\"position\":\"is-bottom\",\"label\":_vm.$t('courseCard.courseStartDate')}},[_c('b-icon',{staticClass:\"icon\",attrs:{\"icon\":\"calendar-today\",\"size\":\"is-small\"}}),(_vm.course.begins)?_c('span',[_vm._v(\" \"+_vm._s(_vm._f(\"date\")(_vm.course.begins))+\" \")]):_c('span',[_vm._v(\" \"+_vm._s(((_vm.$t('courseCard.notprovided')) + \" \"))+\" \")])],1)],1),(_vm.formattedWeekdays.length !== 0)?_c('span',{staticClass:\"info\"},[_c('b-icon',{staticClass:\"icon left-margin\",attrs:{\"icon\":\"calendar-clock\",\"size\":\"is-small\"}}),(_vm.formattedWeekdays.length === 7)?_c('span',[_vm._v(\" \"+_vm._s(_vm.$t('courseCard.monday'))+\"–\"+_vm._s(_vm.$t('courseCard.sunday'))+\" \")]):_vm._e(),(_vm.formattedWeekdays.length < 2)?_c('span',_vm._l((_vm.sortBy('weekday', _vm.formattedWeekdays)),function(day){return _c('span',{key:String(day.weekday) + day.times[0].begins},[(day.weekday)?_c('span',{staticClass:\"weekday\"},[_vm._v(\" \"+_vm._s(_vm.$d(day.weekday, 'weekdayShort') + ' ')+\" \")]):_vm._e(),(day.times.length > 0 && day.times.length < 2)?_c('span',[_vm._v(\" \"+_vm._s(day.times[0].begins)+\"–\"+_vm._s(day.times[0].ends)+\" \")]):_vm._e()])}),0):_vm._e(),(\n _vm.formattedWeekdays.length > 1 && _vm.formattedWeekdays.length < 7\n )?_c('span',_vm._l((_vm.sortBy('weekday', _vm.formattedWeekdays)),function(day){return _c('span',{key:String(day.weekday)},[(day.weekday)?_c('span',{staticClass:\"weekday\"},[_vm._v(\" \"+_vm._s(_vm.$d(day.weekday, 'weekdayShort') + ' ')+\" \")]):_vm._e()])}),0):_vm._e()],1):_vm._e()])])],1)],1):_c('div',[_c('b-skeleton',{attrs:{\"width\":\"100%\",\"height\":\"136px\",\"animated\":true}}),_c('div',{staticClass:\"card-content\"},[_c('b-skeleton',{attrs:{\"width\":\"40%\",\"animated\":true}}),_c('b-skeleton',{attrs:{\"width\":\"60%\",\"animated\":true}}),_c('b-skeleton',{attrs:{\"width\":\"90%\",\"animated\":true}})],1)],1)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import { isEmpty } from 'lodash/fp';\n\nimport { router } from '../router';\n\nfunction useRouter() {\n function pushRoute({\n keyword = router.currentRoute.query.q,\n location = router.currentRoute.query.location,\n distance = router.currentRoute.query.distance,\n weekdays = router.currentRoute.query.weekdays,\n semester = router.currentRoute.query.semester,\n languages = router.currentRoute.query.languages,\n classifications = router.currentRoute.query.classifications,\n serviceProviders = router.currentRoute.query.serviceproviders,\n distanceLearning = router.currentRoute.query.distancelearning,\n page = router.currentRoute.query.page\n }) {\n const p = {\n query: {\n q: isEmpty(keyword) ? undefined : keyword,\n location: isEmpty(location) ? undefined : location,\n distance: isEmpty(distance) ? undefined : distance,\n weekdays: isEmpty(weekdays) ? undefined : weekdays,\n semester: isEmpty(semester) ? undefined : semester,\n languages: isEmpty(languages) ? undefined : languages,\n classifications: isEmpty(classifications) ? undefined : classifications,\n serviceproviders: isEmpty(serviceProviders)\n ? undefined\n : serviceProviders,\n distancelearning: isEmpty(distanceLearning)\n ? undefined\n : distanceLearning,\n page: page === '1' ? undefined : page\n }\n };\n router.push(p);\n }\n\n function goToFrontPage() {\n const { language } = router.currentRoute.params;\n router.push(`/${language}`);\n }\n\n function goToCourse(id: number) {\n const { language } = router.currentRoute.params;\n router.push(`/${language}/course/${id}`);\n }\n\n function getCourseLink(id: number) {\n const { language } = router.currentRoute.params;\n return `/${language}/course/${id}`;\n }\n\n return { pushRoute, goToFrontPage, goToCourse, getCourseLink };\n}\n\nexport default useRouter;\n","import ajoneuvoImage from '../../../frontend-assets/luokitukset-kuvat/23ajoneuvo-ja_kuljetusala.png';\nimport historiaImage from '../../../frontend-assets/luokitukset-kuvat/13historia_ja_arkeologia.png';\nimport humanistinenImage from '../../../frontend-assets/luokitukset-kuvat/24humanistinen_ja_kasvatusala.png';\nimport kadentaidotImage from '../../../frontend-assets/luokitukset-kuvat/2kaden_taidot.png';\nimport kansalaisImage from '../../../frontend-assets/luokitukset-kuvat/29kansalais-ja_jarjestotoiminta.png';\nimport kieletImage from '../../../frontend-assets/luokitukset-kuvat/4kielet.png';\nimport kirjallisuusImage from '../../../frontend-assets/luokitukset-kuvat/11kirjallisuus.png';\nimport kotitalousImage from '../../../frontend-assets/luokitukset-kuvat/17kotitalous-ja_kuluttajapalvelut.png';\nimport kulttuuriImage from '../../../frontend-assets/luokitukset-kuvat/19muu_kulttuurialan_koulutus.png';\nimport kuvataideImage from '../../../frontend-assets/luokitukset-kuvat/5kuvataide.png';\nimport liiketalousImage from '../../../frontend-assets/luokitukset-kuvat/28liiketalous_ja_kauppa.png';\nimport liikuntaImage from '../../../frontend-assets/luokitukset-kuvat/1liikunta_ja_urheilu.png';\nimport luokittelemattomatImage from '../../../frontend-assets/luokitukset-kuvat/9luokittelemattomat.png';\nimport luontoImage from '../../../frontend-assets/luokitukset-kuvat/22luonto-ja_ymparistoala.png';\nimport musiikkiImage from '../../../frontend-assets/luokitukset-kuvat/3musiikki.png';\nimport opetusImage from '../../../frontend-assets/luokitukset-kuvat/12opetus.png';\nimport perusopetusImage from '../../../frontend-assets/luokitukset-kuvat/20perusopetus.png';\nimport poliisiImage from '../../../frontend-assets/luokitukset-kuvat/26poliisi-ja_vartiointiala.png';\nimport puutarhaImage from '../../../frontend-assets/luokitukset-kuvat/16puutarhatalous_ja_puutarhanhoito.png';\nimport ruokaImage from '../../../frontend-assets/luokitukset-kuvat/8ruoka_ja_juoma.png';\nimport sosiaaliImage from '../../../frontend-assets/luokitukset-kuvat/14sosiaali-terveys-ja_liikunta-ala.png';\nimport tanssiImage from '../../../frontend-assets/luokitukset-kuvat/6tanssi_ja_teatteri.png';\nimport tektiiliImage from '../../../frontend-assets/luokitukset-kuvat/30tekstiili-ja_vaatetusala.png';\nimport terveysImage from '../../../frontend-assets/luokitukset-kuvat/10terveys.png';\nimport tietoImage from '../../../frontend-assets/luokitukset-kuvat/15tieto-ja_tietoliikennetekniikka.png';\nimport tietotekniikkaImage from '../../../frontend-assets/luokitukset-kuvat/7tietotekniikka.png';\nimport vapaaaikaImage from '../../../frontend-assets/luokitukset-kuvat/25vapaa-aika-jaa_nuorisotyo.png';\nimport viestintäImage from '../../../frontend-assets/luokitukset-kuvat/27viestinta-ja_informaatioala.png';\nimport yhteiskunnallinenImage from '../../../frontend-assets/luokitukset-kuvat/21yhteiskunnalliset_aineet.png';\nimport yleissivistäväImage from '../../../frontend-assets/luokitukset-kuvat/18muu_yleissivistava_koulutus.png';\n\nexport const DEFAULT_COLOR = '#6987C9';\nexport const DEFAULT_IMAGE = luokittelemattomatImage;\n\nexport const educationSectorMappings: {\n [key: number]: { imageUrl: string; name: string; color: string };\n} = {\n 752: {\n imageUrl: liikuntaImage,\n name: 'Liikunta ja urheilu',\n color: '#23967F'\n },\n 201: {\n imageUrl: kadentaidotImage,\n name: 'Kaden taidot',\n color: '#402E2A'\n },\n 205: {\n imageUrl: musiikkiImage,\n name: 'Musiikki',\n color: '#6987C9'\n },\n 10201: {\n imageUrl: kieletImage,\n name: 'Kielitiede',\n color: '#FFBF00'\n },\n 10202: {\n imageUrl: kieletImage,\n name: 'Suomi',\n color: '#D14081'\n },\n 10203: {\n imageUrl: kieletImage,\n name: 'Ruotsi',\n color: '#23967F'\n },\n 10204: {\n imageUrl: kieletImage,\n name: 'Englanti',\n color: '#402E2A'\n },\n 10205: {\n imageUrl: kieletImage,\n name: 'Saksa',\n color: '#FFBF00'\n },\n 10206: {\n imageUrl: kieletImage,\n name: 'Ranska',\n color: '#6987C9'\n },\n 10207: {\n imageUrl: kieletImage,\n name: 'Venäjä',\n color: '#402E2A'\n },\n 10208: {\n imageUrl: kieletImage,\n name: 'Espanja',\n color: '#D14081'\n },\n 10209: {\n imageUrl: kieletImage,\n name: 'Italia',\n color: '#23967F'\n },\n 10299: {\n imageUrl: kieletImage,\n name: 'Muut kielet',\n color: '#402E2A'\n },\n 206: {\n imageUrl: kuvataideImage,\n name: 'Kuvataide',\n color: '#FFBF00'\n },\n 505: {\n imageUrl: kuvataideImage,\n name: 'Graafinen ja viestintätekniikka',\n color: '#D14081'\n },\n 204: {\n imageUrl: tanssiImage,\n name: 'Tanssi ja teatteri',\n color: '#23967F'\n },\n 40201: {\n imageUrl: tietotekniikkaImage,\n name: 'Tietokoneen ajokorttikoulutu',\n color: '#402E2A'\n },\n 40299: {\n imageUrl: tietotekniikkaImage,\n name: 'Muu tietotekniikan hyväksikäyttö',\n color: '#6987C9'\n },\n 801: {\n imageUrl: ruokaImage,\n name: 'Matkailuala',\n color: '#FFBF00'\n },\n 802: {\n imageUrl: ruokaImage,\n name: 'Majoitus- ja ravitsemisala sekä ruoan valmistus',\n color: '#D14081'\n },\n 899: {\n imageUrl: ruokaImage,\n name: 'Muu matkailu-, ravitsemis- ja talousalan koulutus',\n color: '#23967F'\n },\n 304: {\n imageUrl: luokittelemattomatImage,\n name: 'Tilastointi ja tilastotiede',\n color: '#402E2A'\n },\n 401: {\n imageUrl: luokittelemattomatImage,\n name: 'Matematiikka',\n color: '#6987C9'\n },\n 451: {\n imageUrl: luokittelemattomatImage,\n name: 'Fysiikka ja kemia sekä geo-, avaruus- ja tähtitiet',\n color: '#FFBF00'\n },\n 499: {\n imageUrl: luokittelemattomatImage,\n name: 'Muu luonnontietteiden alan koulutus',\n color: '#D14081'\n },\n 501: {\n imageUrl: luokittelemattomatImage,\n name: 'Arkkitehtuuri ja rakentaminen',\n color: '#23967F'\n },\n 502: {\n imageUrl: luokittelemattomatImage,\n name: 'Kone-, metalli- ja energiatekniikka',\n color: '#6987C9'\n },\n 506: {\n imageUrl: luokittelemattomatImage,\n name: 'Elintarvikeala ja biotekniikka',\n color: '#402E2A'\n },\n 507: {\n imageUrl: luokittelemattomatImage,\n name: 'Prosessi-, kemian ja materiaalitekniikka',\n color: '#FFBF00'\n },\n 599: {\n imageUrl: luokittelemattomatImage,\n name: 'Muu tekniikan ja liikenteen alan koulutus',\n color: '#23967F'\n },\n 710: {\n imageUrl: luokittelemattomatImage,\n name: 'Kauneudenhoitoala',\n color: '#D14081'\n },\n 999: {\n imageUrl: luokittelemattomatImage,\n name: 'Muu koulutus',\n color: '#402E2A'\n },\n 751: {\n imageUrl: terveysImage,\n name: 'Terveysala ja hammashuolto',\n color: '#FFBF00'\n },\n 753: {\n imageUrl: terveysImage,\n name: 'Farmasia ja muu lääkehuolto sekä tekniset terveysp',\n color: '#6987C9'\n },\n 709: {\n imageUrl: terveysImage,\n name: 'eläinlääketiede',\n color: '#D14081'\n },\n 203: {\n imageUrl: kirjallisuusImage,\n name: 'Kirjallisuus',\n color: '#402E2A'\n },\n 3: {\n imageUrl: opetusImage,\n name: 'Lukiokoulutus',\n color: '#23967F'\n },\n 51: {\n imageUrl: opetusImage,\n name: 'Oppimisvalmiuksien kehittäminen ja motivointi',\n color: '#6987C9'\n },\n 103: {\n imageUrl: historiaImage,\n name: 'Historia ja arkeologia',\n color: '#FFBF00'\n },\n 305: {\n imageUrl: sosiaaliImage,\n name: 'Sosiaalitieteet',\n color: '#D14081'\n },\n 701: {\n imageUrl: sosiaaliImage,\n name: 'Sosiaaliala',\n color: '#23967F'\n },\n 799: {\n imageUrl: sosiaaliImage,\n name: 'Muu sosiaali-, terveys- ja liikunta-alan koulutus',\n color: '#402E2A'\n },\n 503: {\n imageUrl: tietoImage,\n name: 'Sähkö- ja automaatiotekniikka',\n color: '#FFBF00'\n },\n 504: {\n imageUrl: tietoImage,\n name: 'Tieto- ja tietoliikennetekniikka',\n color: '#6987C9'\n },\n 602: {\n imageUrl: puutarhaImage,\n name: 'Puutarhatalous ja puutarhanhoito',\n color: '#23967F'\n },\n 851: {\n imageUrl: kotitalousImage,\n name: 'Kotitalous- ja kuluttajapalvelut',\n color: '#D14081'\n },\n 99: {\n imageUrl: yleissivistäväImage,\n name: 'Muu yleissivistävä koulutus',\n color: '#402E2A'\n },\n 207: {\n imageUrl: kulttuuriImage,\n name: 'Kulttuurin- ja taiteiden tutkimus',\n color: '#6987C9'\n },\n 299: {\n imageUrl: kulttuuriImage,\n name: 'Muu kulttuurialan koulutus',\n color: '#FFBF00'\n },\n 2: {\n imageUrl: perusopetusImage,\n name: 'Perusopetus',\n color: '#23967F'\n },\n 104: {\n imageUrl: yhteiskunnallinenImage,\n name: 'Filosofia',\n color: '#D14081'\n },\n 107: {\n imageUrl: yhteiskunnallinenImage,\n name: 'Teologia',\n color: '#402E2A'\n },\n 30399: {\n imageUrl: yhteiskunnallinenImage,\n name: 'Muu hallinnon alan koulutus',\n color: '#6987C9'\n },\n 306: {\n imageUrl: yhteiskunnallinenImage,\n name: 'Politiikka ja politiikkatieteet',\n color: '#23967F'\n },\n 307: {\n imageUrl: yhteiskunnallinenImage,\n name: 'Oikeuskäytäntö ja oikeustieteet',\n color: '#FFBF00'\n },\n 399: {\n imageUrl: yhteiskunnallinenImage,\n name: 'Muu yhteiskunnallisten aineiden, liiketalouden ja',\n color: '#D14081'\n },\n 302: {\n imageUrl: yhteiskunnallinenImage,\n name: 'Kansantalous',\n color: '#23967F'\n },\n 452: {\n imageUrl: luontoImage,\n name: 'Biologia ja maantiede',\n color: '#402E2A'\n },\n 651: {\n imageUrl: luontoImage,\n name: 'Maatila- ja metsätalous',\n color: '#23967F'\n },\n 603: {\n imageUrl: luontoImage,\n name: 'Kalatalous ja kalastus',\n color: '#6987C9'\n },\n 605: {\n imageUrl: luontoImage,\n name: 'Luonto- ja ympäristöala',\n color: '#FFBF00'\n },\n 699: {\n imageUrl: luontoImage,\n name: 'Muu luonnonvara- ja ympäristöalan koulutus',\n color: '#D14081'\n },\n 509: {\n imageUrl: ajoneuvoImage,\n name: 'Ajoneuvo- ja kuljetusala',\n color: '#402E2A'\n },\n 151: {\n imageUrl: humanistinenImage,\n name: 'Opetus- ja kasvatustyö ja psykologia',\n color: '#D14081'\n },\n 199: {\n imageUrl: humanistinenImage,\n name: 'Muu humanistisen ja kasvatusalan koulutus',\n color: '#FFBF00'\n },\n 101: {\n imageUrl: vapaaaikaImage,\n name: 'Vapaa-aika- ja nuorisotyö',\n color: '#6987C9'\n },\n 951: {\n imageUrl: poliisiImage,\n name: 'Poliisi- ja vartiointiala',\n color: '#6987C9'\n },\n 901: {\n imageUrl: poliisiImage,\n name: 'Sotilas- ja rajavartioala',\n color: '#23967F'\n },\n 902: {\n imageUrl: poliisiImage,\n name: 'Palo- ja pelastusala',\n color: '#D14081'\n },\n 202: {\n imageUrl: viestintäImage,\n name: 'Viestintä- ja informaatioala',\n color: '#402E2A'\n },\n 301: {\n imageUrl: liiketalousImage,\n name: 'Liiketalous ja kauppa',\n color: '#6987C9'\n },\n 351: {\n imageUrl: liiketalousImage,\n name: 'Yrittäjyys ja yrittäjäkasvatus',\n color: '#D14081'\n },\n 510: {\n imageUrl: liiketalousImage,\n name: 'Tuotantotalous',\n color: '54'\n },\n 30301: {\n imageUrl: kansalaisImage,\n name: 'Kansalais- ja järjestötoiminta',\n color: '#FFBF00'\n },\n 508: {\n imageUrl: tektiiliImage,\n name: 'Tekstiili- ja vaatetusala',\n color: '#D14081'\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!./course-card.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!./course-card.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./course-card.vue?vue&type=template&id=588b5220&scoped=true\"\nimport script from \"./course-card.vue?vue&type=script&lang=ts\"\nexport * from \"./course-card.vue?vue&type=script&lang=ts\"\nimport style0 from \"./course-card.vue?vue&type=style&index=0&id=588b5220&prod&scoped=true&lang=css\"\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 \"588b5220\",\n null\n \n)\n\nexport default component.exports","\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!./course-list.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!./course-list.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./course-list.vue?vue&type=template&id=c345d58c&scoped=true\"\nimport script from \"./course-list.vue?vue&type=script&lang=ts\"\nexport * from \"./course-list.vue?vue&type=script&lang=ts\"\nimport style0 from \"./course-list.vue?vue&type=style&index=0&id=c345d58c&prod&scoped=true&lang=css\"\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 \"c345d58c\",\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',{staticClass:\"button-group\"},[_c('SearchFilterDropdown',{attrs:{\"type\":\"distanceLearning\",\"initialSelection\":[_vm.distanceLearning],\"options\":_vm.distanceLearningList}}),_c('SearchFilterDropdown',{attrs:{\"type\":\"weekdays\",\"initialSelection\":_vm.weekdays,\"options\":_vm.weekdaysList}}),_c('SearchFilterDropdown',{attrs:{\"type\":\"semester\",\"initialSelection\":[_vm.semester],\"options\":_vm.semestersList}}),_c('SearchFilterDropdown',{attrs:{\"type\":\"classifications\",\"initialSelection\":_vm.classifications,\"options\":_vm.classificationsList}}),_c('SearchFilterDropdown',{attrs:{\"type\":\"serviceProviders\",\"initialSelection\":_vm.serviceProviders,\"options\":_vm.serviceProvidersList}})],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('b-dropdown',{attrs:{\"aria-role\":\"list\",\"scrollable\":\"\",\"max-height\":\"65vh\"},model:{value:(_vm.selected),callback:function ($$v) {_vm.selected=$$v},expression:\"selected\"}},[_c('b-button',{staticClass:\"is-primary filter-button\",attrs:{\"slot\":\"trigger\",\"outlined\":!Boolean(_vm.selected),\"type\":\"button\"},slot:\"trigger\"},[_c('span',[_vm._v(_vm._s(_vm.$t((\"searchFilters.\" + _vm.type))))])]),(_vm.type === 'serviceProviders')?_c('b-dropdown-item',{attrs:{\"custom\":\"\",\"aria-role\":\"listitem\"}},[_c('b-input',{staticClass:\"search\",attrs:{\"placeholder\":_vm.$t('serviceProviders.search')},model:{value:(_vm.searchValue),callback:function ($$v) {_vm.searchValue=$$v},expression:\"searchValue\"}})],1):_vm._e(),(_vm.showSelectedOptionSeparately)?_c('b-dropdown-item',{key:_vm.selected,staticClass:\"filter-item\",attrs:{\"value\":_vm.selected,\"aria-role\":\"listitem\"},on:{\"click\":function($event){return _vm.optionClicked(_vm.selected)}}},[_vm._v(\" \"+_vm._s(_vm.selectedName)+\" \")]):_vm._e(),_vm._l((_vm.filteredOptions),function(option){return _c('b-dropdown-item',{key:option.id.toString(),staticClass:\"filter-item\",attrs:{\"value\":option.id.toString(),\"aria-role\":\"listitem\"},on:{\"click\":function($event){_vm.optionClicked(option.id.toString())}}},[_c('span',[_vm._v(_vm._s(option.name))])])})],2)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./search-filter-dropdown.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!./search-filter-dropdown.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./search-filter-dropdown.vue?vue&type=template&id=3044e8f6&scoped=true\"\nimport script from \"./search-filter-dropdown.vue?vue&type=script&lang=ts\"\nexport * from \"./search-filter-dropdown.vue?vue&type=script&lang=ts\"\nimport style0 from \"./search-filter-dropdown.vue?vue&type=style&index=0&id=3044e8f6&prod&lang=scss&scoped=true\"\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 \"3044e8f6\",\n null\n \n)\n\nexport default component.exports","\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!./search-filters.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!./search-filters.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./search-filters.vue?vue&type=template&id=5eead4c0&scoped=true\"\nimport script from \"./search-filters.vue?vue&type=script&lang=ts\"\nexport * from \"./search-filters.vue?vue&type=script&lang=ts\"\nimport style0 from \"./search-filters.vue?vue&type=style&index=0&id=5eead4c0&prod&lang=scss&scoped=true\"\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 \"5eead4c0\",\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('b-navbar',{staticClass:\"sticky-header\"},[_c('template',{slot:\"brand\"},[_c('Logo',{attrs:{\"width\":\"140px\"}})],1),_c('template',{slot:\"start\"},[_c('b-field',{staticClass:\"search-fields\",attrs:{\"grouped\":\"\"}},[_c('form',{on:{\"submit\":function($event){$event.preventDefault();}}},[_c('b-field',[_c('b-input',{attrs:{\"placeholder\":_vm.$t('searchHeader.searchForCourse'),\"type\":\"search\",\"icon-right\":\"magnify\"},model:{value:(_vm.newKeyword),callback:function ($$v) {_vm.newKeyword=$$v},expression:\"newKeyword\"}})],1),_c('b-field',[_c('b-autocomplete',{attrs:{\"placeholder\":_vm.$t('searchHeader.location'),\"type\":\"search\",\"data\":_vm.locationSuggestions,\"icon-right\":\"map-marker-outline\",\"clearable\":\"\"},model:{value:(_vm.newLocation),callback:function ($$v) {_vm.newLocation=$$v},expression:\"newLocation\"}})],1),_c('b-field',{staticClass:\"field-container\",attrs:{\"grouped\":\"\"}},[_c('b-dropdown',{model:{value:(_vm.newDistance),callback:function ($$v) {_vm.newDistance=$$v},expression:\"newDistance\"}},[_c('b-input',{staticClass:\"distance-search\",attrs:{\"slot\":\"trigger\",\"disabled\":_vm.newLocation === undefined || _vm.newLocation === '',\"type\":\"button\",\"icon-right\":\"arrow-expand\",\"value\":_vm.newLocation\n ? _vm.newDistance + ' km'\n : _vm.$t('searchHeader.distance')},slot:\"trigger\"}),_c('b-dropdown-item',{attrs:{\"value\":10,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"10 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":25,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"25 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":50,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"50 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":100,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"100 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":250,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"250 km\")])])],1)],1),_c('b-field',[_c('b-button',{staticClass:\"is-uppercase search-button\",attrs:{\"native-type\":\"submit\",\"type\":\"is-primary\"},on:{\"click\":_vm.search}},[_vm._v(_vm._s(_vm.$t('searchHeader.search')))])],1)],1)])],1),_c('template',{slot:\"end\"},[_c('b-navbar-item',{attrs:{\"tag\":\"router-link\",\"to\":{ path: (\"/\" + _vm.language + \"/search\") }}},[_vm._v(\" \"+_vm._s(_vm.$t('header.browse')))]),_c('b-navbar-item',{attrs:{\"tag\":\"router-link\",\"to\":{ path: (\"/\" + _vm.language + \"/service-providers\") }}},[_vm._v(\" \"+_vm._s(_vm.$t('header.serviceProviders'))+\" \")]),_c('LanguageSelection')],1)],2)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./search-header-desktop.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!./search-header-desktop.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./search-header-desktop.vue?vue&type=template&id=02755115&scoped=true\"\nimport script from \"./search-header-desktop.vue?vue&type=script&lang=ts\"\nexport * from \"./search-header-desktop.vue?vue&type=script&lang=ts\"\nimport style0 from \"./search-header-desktop.vue?vue&type=style&index=0&id=02755115&prod&lang=scss&scoped=true\"\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 \"02755115\",\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('section',{staticClass:\"wrapper\"},[_c('MobileHeader',{staticClass:\"header-mobile\"}),_c('b-button',{staticClass:\"search-button\",attrs:{\"slot\":\"trigger\",\"rounded\":\"\",\"outline\":\"\",\"tag\":\"a\"},on:{\"click\":function($event){_vm.searchModalActive = true}},slot:\"trigger\"},[_c('div',{staticClass:\"search-parameters\"},[(_vm.keyword)?_c('span',{staticClass:\"search-keyword\"},[_vm._v(_vm._s(_vm.keyword))]):_c('span',{staticClass:\"search-keyword placeholder\"},[_vm._v(_vm._s(_vm.$t('searchHeader.searchForCourse')))]),_c('div',{staticClass:\"dot\"}),(_vm.location)?_c('span',{staticClass:\"search-location\"},[_vm._v(_vm._s(_vm.location))]):_c('span',{staticClass:\"search-location placeholder\"},[_vm._v(_vm._s(_vm.$t('searchHeader.location')))]),(_vm.location)?_c('span',{staticClass:\"search-distance\"},[_vm._v(_vm._s(_vm.newDistance)+\" km \")]):_c('span',{staticClass:\"search-distance placeholder\"},[_vm._v(_vm._s(_vm.$t('searchHeader.distance')))]),_c('b-icon',{staticClass:\"search-icon\",attrs:{\"icon\":\"magnify\",\"size\":\"is-medium\"}})],1)]),_c('b-modal',{attrs:{\"width\":640,\"scroll\":\"keep\"},model:{value:(_vm.searchModalActive),callback:function ($$v) {_vm.searchModalActive=$$v},expression:\"searchModalActive\"}},[_c('div',{staticClass:\"content notification\"},[_c('form',{staticClass:\"search-fields\",on:{\"submit\":function($event){$event.preventDefault();}}},[_c('b-field',[_c('b-input',{attrs:{\"placeholder\":_vm.$t('searchHeader.searchForCourse'),\"type\":\"search\",\"icon-right\":\"magnify\"},model:{value:(_vm.newKeyword),callback:function ($$v) {_vm.newKeyword=$$v},expression:\"newKeyword\"}})],1),_c('b-field',[_c('b-autocomplete',{attrs:{\"placeholder\":_vm.$t('searchHeader.location'),\"type\":\"search\",\"data\":_vm.locationSuggestions,\"icon-right\":\"map-marker-outline\",\"clearable\":\"\"},model:{value:(_vm.newLocation),callback:function ($$v) {_vm.newLocation=$$v},expression:\"newLocation\"}})],1),_c('b-field',{staticClass:\"field-container\",attrs:{\"grouped\":\"\"}},[_c('b-dropdown',{model:{value:(_vm.newDistance),callback:function ($$v) {_vm.newDistance=$$v},expression:\"newDistance\"}},[_c('b-input',{staticClass:\"distance-search\",attrs:{\"slot\":\"trigger\",\"disabled\":_vm.newLocation === undefined || _vm.newLocation === '',\"type\":\"button\",\"icon-right\":\"arrow-expand\",\"value\":_vm.newLocation\n ? _vm.newDistance + ' km'\n : _vm.$t('searchHeader.distance')},slot:\"trigger\"}),_c('b-dropdown-item',{attrs:{\"value\":10,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"10 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":25,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"25 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":50,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"50 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":100,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"100 km\")])]),_c('b-dropdown-item',{attrs:{\"value\":250,\"aria-role\":\"listitem\"}},[_c('span',[_vm._v(\"250 km\")])])],1)],1),_c('b-field',[_c('b-button',{staticClass:\"is-uppercase\",attrs:{\"native-type\":\"submit\",\"type\":\"is-primary\"},on:{\"click\":_vm.search}},[_vm._v(_vm._s(_vm.$t('searchHeader.search')))])],1)],1)])])],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!./search-header-mobile.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!./search-header-mobile.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./search-header-mobile.vue?vue&type=template&id=7ad1eae7&scoped=true\"\nimport script from \"./search-header-mobile.vue?vue&type=script&lang=ts\"\nexport * from \"./search-header-mobile.vue?vue&type=script&lang=ts\"\nimport style0 from \"./search-header-mobile.vue?vue&type=style&index=0&id=7ad1eae7&prod&lang=scss&scoped=true\"\nimport style1 from \"./search-header-mobile.vue?vue&type=style&index=1&id=7ad1eae7&prod&lang=scss\"\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 \"7ad1eae7\",\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('l-map',{key:_vm.zoom + _vm.coordinates.toString(),attrs:{\"zoom\":_vm.zoom,\"center\":[_vm.coordinates.lat, _vm.coordinates.lon],\"options\":_vm.MAP_OPTIONS}},[_c('l-control-zoom'),_c('l-tile-layer',{attrs:{\"url\":_vm.URL}}),(_vm.courses)?_c('v-marker-cluster',{staticClass:\"cluster\"},_vm._l((_vm.markers),function(item,index){return _c('l-marker',{key:index,attrs:{\"vif\":_vm.markers,\"lat-lng\":item.position,\"icon\":_vm.getIcon(item)}},[_c('l-popup',[_c('CourseCard',{key:item.id,attrs:{\"course\":_vm.getCourse(_vm.courses, item.id)}})],1)],1)}),1):_vm._e()],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./search-map.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!./search-map.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./search-map.vue?vue&type=template&id=23dfcadb\"\nimport script from \"./search-map.vue?vue&type=script&lang=ts\"\nexport * from \"./search-map.vue?vue&type=script&lang=ts\"\nimport style0 from \"./search-map.vue?vue&type=style&index=0&id=23dfcadb&prod&lang=scss\"\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('b-pagination',{attrs:{\"total\":_vm.totalNumberOfCourses,\"per-page\":_vm.perPage,\"icon-prev\":_vm.prevIcon,\"icon-next\":_vm.nextIcon,\"range-before\":_vm.currentPage <= 6 ? 6 : 1,\"range-after\":_vm.currentPage < 6 ? 6 - _vm.currentPage : 1,\"aria-next-label\":\"Next page\",\"aria-previous-label\":\"Previous page\",\"aria-page-label\":\"Page\",\"aria-current-label\":\"Current page\"},on:{\"change\":_vm.pushPage},scopedSlots:_vm._u([{key:\"default\",fn:function(props){return _c('b-pagination-button',{directives:[{name:\"show\",rawName:\"v-show\",value:(props.page.number - _vm.currentPage < 50),expression:\"props.page.number - currentPage < 50\"}],attrs:{\"page\":props.page}},[_vm._v(\" \"+_vm._s(props.page.number)+\" \")])}}]),model:{value:(_vm.currentPage),callback:function ($$v) {_vm.currentPage=$$v},expression:\"currentPage\"}})}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./search-pagination.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!./search-pagination.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./search-pagination.vue?vue&type=template&id=7aa2917f\"\nimport script from \"./search-pagination.vue?vue&type=script&lang=ts\"\nexport * from \"./search-pagination.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 (_vm.tenant)?_c('b-collapse',{staticClass:\"card mobile-tenant\",attrs:{\"animation\":\"slide\",\"open\":false,\"aria-id\":_vm.tenant.tenant},scopedSlots:_vm._u([{key:\"trigger\",fn:function(props){return _c('div',{staticClass:\"card-header\",attrs:{\"role\":\"button\",\"aria-controls\":_vm.tenant.tenant}},[_c('p',{staticClass:\"card-header-title\"},[_vm._v(\" \"+_vm._s(_vm.tenant.name)+\" \")]),_c('a',{staticClass:\"card-header-icon\"},[(_vm.detailsText)?_c('span',{staticClass:\"details\"},[_vm._v(_vm._s(_vm.$t('tenantDropdown.details')))]):_vm._e(),_c('b-icon',{attrs:{\"icon\":props.open ? 'menu-up' : 'menu-down'}})],1)])}}],null,false,2669739512)},[_c('div',{staticClass:\"card-content\"},[_c('div',{staticClass:\"info-logo-wrapper\"},[(_vm.tenant.logo)?_c('div',[_c('img',{staticClass:\"logo\",attrs:{\"alt\":\"logo\",\"src\":_vm.tenant.logo}})]):_vm._e(),_c('div',{staticClass:\"info-wrapper\"},[(_vm.tenant.location)?_c('div',{staticClass:\"info\"},[_c('b-icon',{staticClass:\"icon-small\",attrs:{\"icon\":\"map-marker\",\"size\":\"is-small\"}}),_c('div',{staticClass:\"location-info\"},[(_vm.tenant.location.address)?_c('span',[_vm._v(\" \"+_vm._s(_vm.tenant.location.address)+\" \")]):_vm._e(),_c('span',[_vm._v(\" \"+_vm._s([_vm.tenant.location.postalcode, _vm.tenant.location.city] .filter(Boolean) .join(' '))+\" \")])])],1):_vm._e(),(_vm.tenant.phone)?_c('div',{staticClass:\"info\"},[_c('b-icon',{staticClass:\"icon-small\",attrs:{\"icon\":\"phone\",\"size\":\"is-small\"}}),(_vm.phone)?_c('a',{attrs:{\"href\":_vm.phone}},[_vm._v(_vm._s(_vm.tenant.phone))]):_c('span',[_vm._v(_vm._s(_vm.tenant.phone))])],1):_vm._e(),(_vm.tenant.email)?_c('div',{staticClass:\"info\"},[_c('b-icon',{staticClass:\"icon-small\",attrs:{\"icon\":\"email\",\"size\":\"is-small\"}}),_c('a',{attrs:{\"href\":_vm.email}},[_vm._v(\" \"+_vm._s(_vm.tenant.email)+\" \")])],1):_vm._e(),(_vm.tenant.homepage)?_c('div',{staticClass:\"info\"},[_c('b-icon',{staticClass:\"icon-small\",attrs:{\"icon\":\"home\",\"size\":\"is-small\"}}),_c('a',{attrs:{\"href\":_vm.tenant.homepage,\"target\":\"_blank\"}},[_vm._v(\" \"+_vm._s(_vm.tenant.homepage)+\" \")])],1):_vm._e()])]),_c('div',{staticClass:\"links-wrapper\"},[_c('div',{staticClass:\"icons\"},[(_vm.tenant.facebook)?_c('a',{attrs:{\"href\":_vm.tenant.facebook,\"target\":\"_blank\"}},[_c('b-icon',{staticClass:\"icon-large\",attrs:{\"icon\":\"facebook\",\"size\":\"is-medium\"}})],1):_vm._e(),(_vm.tenant.instagram)?_c('a',{attrs:{\"href\":_vm.tenant.instagram,\"target\":\"_blank\"}},[_c('b-icon',{staticClass:\"icon-large\",attrs:{\"icon\":\"instagram\",\"size\":\"is-medium\"}})],1):_vm._e(),(_vm.tenant.linkedin)?_c('a',{attrs:{\"href\":_vm.tenant.linkedin,\"target\":\"_blank\"}},[_c('b-icon',{staticClass:\"icon-large\",attrs:{\"icon\":\"linkedin\",\"size\":\"is-medium\"}})],1):_vm._e(),(_vm.tenant.twitter)?_c('a',{attrs:{\"href\":_vm.tenant.twitter,\"target\":\"_blank\"}},[_c('b-icon',{staticClass:\"icon-large\",attrs:{\"icon\":\"twitter\",\"size\":\"is-medium\"}})],1):_vm._e()]),(_vm.browseLink)?_c('router-link',{staticClass:\"router-style\",attrs:{\"to\":{\n path: (\"/\" + _vm.language + \"/search?serviceproviders=\" + (_vm.tenant.tenant))\n }}},[_c('b-button',{staticClass:\"is-primary button-style\"},[_vm._v(\" \"+_vm._s(_vm.$t('serviceProviders.browse'))+\" \")]),_c('span',{staticClass:\"is-primary browse-style\"},[_vm._v(\" \"+_vm._s(_vm.$t('serviceProviders.browse'))+\" \")])],1):_vm._e()],1)])]):_vm._e()}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./tenant-dropdown.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!./tenant-dropdown.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./tenant-dropdown.vue?vue&type=template&id=7b458b0c&scoped=true\"\nimport script from \"./tenant-dropdown.vue?vue&type=script&lang=ts\"\nexport * from \"./tenant-dropdown.vue?vue&type=script&lang=ts\"\nimport style0 from \"./tenant-dropdown.vue?vue&type=style&index=0&id=7b458b0c&prod&lang=scss&scoped=true\"\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 \"7b458b0c\",\n null\n \n)\n\nexport default component.exports","\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!./search.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!./search.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./search.vue?vue&type=template&id=574c0f53&scoped=true\"\nimport script from \"./search.vue?vue&type=script&lang=ts\"\nexport * from \"./search.vue?vue&type=script&lang=ts\"\nimport style0 from \"./search.vue?vue&type=style&index=0&id=574c0f53&prod&lang=scss&scoped=true\"\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 \"574c0f53\",\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'),(_vm.tenants)?_c('div',{staticClass:\"wrapper\"},[_c('b-field',[_c('b-input',{staticClass:\"search\",attrs:{\"placeholder\":_vm.$t('serviceProviders.search'),\"type\":\"is-primary\",\"icon-right\":\"magnify\"},model:{value:(_vm.searchValue),callback:function ($$v) {_vm.searchValue=$$v},expression:\"searchValue\"}})],1),_c('div',{staticClass:\"tenants\"},_vm._l((_vm.filteredTenants),function(tenant){return _c('div',{key:tenant.tenant},[_c('TenantDropdown',{attrs:{\"tenant\":tenant,\"browseLink\":true,\"detailsText\":false}})],1)}),0)],1):_vm._e(),_c('Footer')],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\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!./service-providers.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!./service-providers.vue?vue&type=script&lang=ts\"","import { render, staticRenderFns } from \"./service-providers.vue?vue&type=template&id=3b37ff00&scoped=true\"\nimport script from \"./service-providers.vue?vue&type=script&lang=ts\"\nexport * from \"./service-providers.vue?vue&type=script&lang=ts\"\nimport style0 from \"./service-providers.vue?vue&type=style&index=0&id=3b37ff00&prod&scoped=true&lang=css\"\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 \"3b37ff00\",\n null\n \n)\n\nexport default component.exports","import VueRouter, { Route, RouteConfig } from 'vue-router';\n\nimport Course from './views/course.vue';\nimport Index from './views/index.vue';\nimport Language from './views/language.vue';\nimport NotFound from './views/not-found.vue';\nimport Search from './views/search.vue';\nimport ServiceProviders from './views/service-providers.vue';\nimport Vue from 'vue';\n\nVue.use(VueRouter);\n\nconst routes: RouteConfig[] = [\n {\n path: '/',\n // TODO: Redirect to a specific saved in Local or Session Storage?\n redirect: '/fi'\n },\n {\n path: '/:language',\n component: Language,\n props: true,\n children: [\n {\n path: '/',\n name: 'index',\n props: true,\n component: Index\n },\n {\n path: '/:language/search',\n name: 'search',\n props: true,\n component: Search\n },\n {\n path: '/:language/service-providers',\n name: 'service-providers',\n props: true,\n component: ServiceProviders\n },\n {\n path: '/:language/course/:id',\n name: 'course',\n props: true,\n component: Course\n },\n {\n path: '/:language/404',\n name: '404',\n props: true,\n component: NotFound\n },\n {\n path: '*',\n redirect: '404'\n }\n ]\n }\n];\n\ninterface VueRouterExtended extends VueRouter {\n /**\n * Route where the user was previously.\n */\n previousRoute?: Route;\n /**\n * Go back to the previous page if there is a previous page\n * in our service, if not, then go to frontpage.\n */\n backOrFrontpage: () => void;\n}\n\n/**\n * Get a monkey-patched router with referer and function to\n * go back or to frontpage.\n *\n * @returns\n */\nconst getRouter = (): VueRouterExtended => {\n const r = new VueRouter({\n mode: 'history',\n routes,\n scrollBehavior() {\n return { x: 0, y: 0 };\n }\n }) as VueRouterExtended;\n\n r.beforeEach((to, from, next) => {\n r.previousRoute = from;\n next();\n });\n\n r.backOrFrontpage = () => {\n // previousRoute might be there if there actually wasn't a previous\n // route, but if it is, its name is null\n if (r.previousRoute?.name) {\n r.back();\n } else if (r.currentRoute.params.language) {\n r.push({\n name: 'index',\n params: { language: r.currentRoute.params.language }\n });\n } else {\n r.push({ name: 'index' });\n }\n };\n\n return r;\n};\n\nexport const router = getRouter();\n","import VueI18n from 'vue-i18n';\nimport { router } from './router';\n\nimport { default as messages } from '../frontend-assets/i18n.json';\n\nexport const initializeI18n = () =>\n new VueI18n({\n locale: 'fi',\n fallbackLocale: 'fi',\n numberFormats: {\n fi: {\n currency: {\n style: 'currency',\n currency: 'EUR'\n }\n },\n sv: {\n currency: {\n style: 'currency',\n currency: 'EUR'\n }\n },\n en: {\n currency: {\n style: 'currency',\n currency: 'EUR'\n }\n }\n },\n dateTimeFormats: {\n fi: {\n weekdayShort: {\n weekday: 'short'\n },\n weekdayLong: {\n weekday: 'long'\n }\n },\n en: {\n weekdayShort: {\n weekday: 'short'\n },\n weekdayLong: {\n weekday: 'long'\n }\n },\n sv: {\n weekdayShort: {\n weekday: 'short'\n },\n weekdayLong: {\n weekday: 'long'\n }\n }\n },\n silentFallbackWarn: true,\n messages\n });\n\nexport const changeLanguage = (language: 'fi' | 'sv' | 'en') => {\n router.push({ params: { language } });\n // Force a refresh, because pushing the params doesn't necessarily refresh the contents\n router.go(0);\n};\n","import 'leaflet/dist/leaflet.css';\n\nimport {\n formatDate,\n formatDateRange,\n formatDateTime,\n formatDateTimeRange,\n formatMidnight,\n formatPrice,\n formatTime,\n formatTimeRange\n} from './filters';\n\nimport App from './App.vue';\nimport Buefy from 'buefy';\nimport Meta from 'vue-meta';\nimport Vue from 'vue';\nimport VueCompositionApi from '@vue/composition-api';\nimport VueI18n from 'vue-i18n';\nimport { capitalize } from 'lodash/fp';\nimport { initializeI18n } from './i18n';\nimport { router } from './router';\n\nVue.use(Buefy);\nVue.use(Meta);\nVue.use(VueCompositionApi);\nVue.use(VueI18n);\n\nVue.config.productionTip = false;\n\nVue.filter('capitalize', capitalize);\nVue.filter('date', formatDate);\nVue.filter('dateRange', formatDateRange);\nVue.filter('dateTime', formatDateTime);\nVue.filter('dateTimeRange', formatDateTimeRange);\nVue.filter('time', formatTime);\nVue.filter('timeRange', formatTimeRange);\nVue.filter('price', formatPrice);\nVue.filter('midnight', formatMidnight);\n\nnew Vue({\n i18n: initializeI18n(),\n router,\n render: (h) => h(App)\n}).$mount('#app');\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\tloaded: false,\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Flag the module as loaded\n\tmodule.loaded = true;\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","var deferred = [];\n__webpack_require__.O = (result, chunkIds, fn, priority) => {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar [chunkIds, fn, priority] = deferred[i];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.nmd = (module) => {\n\tmodule.paths = [];\n\tif (!module.children) module.children = [];\n\treturn module;\n};","__webpack_require__.p = \"/static/kurssit.kansalaisopistot.fi/\";","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t143: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = (parentChunkLoadingFunction, data) => {\n\tvar [chunkIds, moreModules, runtime] = data;\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some((id) => (installedChunks[id] !== 0))) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunklinnunrata\"] = self[\"webpackChunklinnunrata\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [998], () => (__webpack_require__(62714)))\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["DATE_FORMAT_FI","DATETIME_FORMAT_FI","TIME_FORMAT_FI","formatTime","date","isValid","format","formatDate","formatDateTime","formatTimeRange","begins","ends","concat","formatDateRange","isSameDay","beginsFormat","isSameMonth","isSameYear","formatDateTimeRange","formatMidnight","getTime","startOfDay","subMinutes","formatPrice","price","toLocaleString","style","currency","maximumFractionDigits","minimumFractionDigits","render","_vm","this","_h","$createElement","_c","_self","attrs","staticRenderFns","defineComponent","name","metaInfo","title","messages","component","staticClass","_e","isLoading","course","domProps","_s","path","language","_v","tenantName","teacher","description","_l","sortBy","periods","period","key","keywords","some","keyword","includes","length","lessons","location","address","city","filter","Boolean","join","latlon","BASE_PATH","replace","isBlob","value","Blob","BaseAPI","_this","configuration","arguments","undefined","Configuration","_classCallCheck","fetchApi","_ref","_asyncToGenerator","_regeneratorRuntime","mark","_callee","url","init","fetchParams","_iterator","_step","middleware","response","_iterator2","_step2","_middleware","wrap","_context","prev","next","_createForOfIteratorHelper","s","n","done","pre","_objectSpread","fetch","t0","sent","t1","e","f","finish","post","clone","t2","t3","abrupt","stop","_x","_x2","apply","_createClass","_next$middleware","_len","preMiddlewares","Array","_key","middlewares","map","withMiddleware","_toConsumableArray","_len2","postMiddlewares","_key2","_request","_callee2","context","_this$createFetchPara","_context2","createFetchParams","status","request","_x3","basePath","query","Object","keys","queryParamsStringify","body","FormData","URLSearchParams","JSON","stringify","headers","assign","method","credentials","constructor","slice","RequiredError","_Error","field","msg","_this2","_callSuper","_inherits","_wrapNativeSuper","Error","get","window","bind","querystring","username","password","apiKey","accessToken","exists","json","params","prefix","fullKey","multiValue","singleValue","encodeURIComponent","String","part","ErrorItemType","JSONApiResponse","raw","transformer","jsonValue","_value","_callee3","_context3","call","GeopointFromJSON","GeopointFromJSONTyped","ignoreDiscriminator","HellewiCartItemType","HellewiCatalogFromJSON","HellewiCatalogFromJSONTyped","HellewiCatalogItemFromJSON","HellewiCatalogItemFromJSONTyped","HellewiCatalogItemTypeFromJSON","HellewiCatalogItemType","HellewiCatalogItemTypeFromJSONTyped","HellewiCatalogSettingsFromJSON","HellewiCatalogSettingsFromJSONTyped","HellewiCatalogSettingsEnabledCatalogItemTypesFromJSON","HellewiCatalogSettingsEnabledCatalogItemTypesFromJSONTyped","HellewiCourseNotificationLabel","HellewiCourseStatus","HellewiCourseFromJSON","HellewiCourseFromJSONTyped","HellewiCourseStatusFromJSON","Date","HellewiCourseDayFromJSON","HellewiLocationFromJSON","HellewiCourseNotificationFromJSON","HellewiCoursePeriodFromJSON","HellewiLanguageFromJSON","HellewiTagFromJSON","HellewiCoursePriceFromJSON","HellewiCoursePartialFromJSON","HellewiCourseLessonFromJSON","HellewiParticipantCountFromJSON","HellewiCourseCountFromJSON","HellewiCourseCountFromJSONTyped","HellewiCourseDayFromJSONTyped","WeekdayFromJSON","HellewiCourseLessonFromJSONTyped","HellewiCourseMinimalFromJSON","HellewiCourseMinimalFromJSONTyped","HellewiCourseMinimalParentFromJSON","HellewiCourseMinimalParentFromJSONTyped","HellewiCourseNotificationFromJSONTyped","HellewiCourseNotificationLabelFromJSON","HellewiCourseNotificationLabelFromJSONTyped","HellewiCoursePartialFromJSONTyped","HellewiCoursePeriodFromJSONTyped","HellewiCoursePriceFromJSONTyped","HellewiCoursePriceInstallmentFromJSON","HellewiCoursePriceInstallmentFromJSONTyped","HellewiCoursePriceInstallmentInstallmentsFromJSON","HellewiCoursePriceInstallmentInstallmentsFromJSONTyped","HellewiCourseStatusFromJSONTyped","HellewiLanguageFromJSONTyped","HellewiLocationFromJSONTyped","HellewiParticipantCountFromJSONTyped","PurchaseProductItemType","PurchaseProductType","Weekday","HellewiTagFromJSONTyped","HellewiTenantFromJSON","HellewiTenantFromJSONTyped","WeekdayFromJSONTyped","RequestState","CatalogApi","_runtime$BaseAPI","_getCatalogRaw","requestParameters","queryParameters","headerParameters","q","runtime","getCatalogRaw","_getCatalog","getCatalog","_getCatalogSettingsRaw","getCatalogSettingsRaw","_getCatalogSettings","_callee4","_context4","getCatalogSettings","CourseApi","_getCourseRaw","id","getCourseRaw","_getCourse","getCourse","_getCourseCountRaw","getCourseCountRaw","_getCourseCount","getCourseCount","_x4","_listCourseParticipantCountsRaw","_callee5","_context5","ids","listCourseParticipantCountsRaw","_x5","_listCourseParticipantCounts","_callee6","_context6","listCourseParticipantCounts","_x6","_listCoursesRaw","_callee7","_context7","page","limit","sort","sortdir","listCoursesRaw","_x7","_listCourses","_callee8","_context8","listCourses","_x8","TenantApi","_listTenantsRaw","listTenantsRaw","_listTenants","listTenants","filterUndefineds","xs","x","translate","i18nKey","parent","$t","translation","toString","stateHasError","state","computed","stateIsLoading","Loading","ApiEndpointInitialization","api","initial","initialize","Initialized","Uninitialized","onBeforeMount","watch","useErrorToast","ctx","warnComponents","ref","warnToast","push","Snackbar","open","message","duration","type","position","actionText","indefinite","queue","clearErrorToasts","close","err","useCourseApi","memoize","changeConfiguration","useGetCourseCount","_useCourseApi","execute","Success","useGetCourse","_useCourseApi2","_ref2","_response$value","useListCourses","count","courses","locations","_useCourseApi3","currentParams","ongoing","_ref3","isEqual","cancel","PCancelable","_ref4","resolve","reject","onCancel","responseRaw","partialCourses","participantCounts","isEmpty","Math","min","parseInt","participantcount","find","pc","slot","on","$event","changeLanguage","setup","serviceName","width","props","router","currentRoute","components","LanguageSelection","Logo","goBack","logoWidth","menuModalActive","model","callback","$$v","expression","windowWidth","innerWidth","onWidthChange","onMounted","addEventListener","onUnmounted","removeEventListener","backOrFrontpage","$tc","totalCourseCount","_useGetCourseCount","center","MAP_OPTIONS","URL","markerIcon","text","zoomSnap","scrollWheelZoom","zoomControl","LMap","LTileLayer","LMarker","LControlZoom","LTooltip","coordinates","required","latLng","lat","lon","divIcon","className","iconSize","html","colors","primaryColor","Availability","_f","formattedWeekdays","day","weekday","$d","times","scopedSlots","_u","fn","time","class","availability","registrationbegins","registrationendssoft","registrationlink","registrationopen","getDefaultPrice","prices","_default","getPriceEuros","amount","currentYear","getFullYear","nextYear","currentMonth","getMonth","formatWeekdays","Map","days","groupedDays","setISODay","values","groupBy","getAvailability","full","sparefull","sparesAvailable","almostfull","available","registrationClosed","_props$course","_props$course2","lessoncount","row","_props$period$lessons","_props$course$lessons","Header","MobileHeader","Footer","CourseMap","RegistrationBox","LessonsCollapse","_useGetCourse","hasError","checkError","error","_course$value","tenantCi","ci","Tenant","catalogitems","onLocatingError","onLocatingSuccessful","popularClassifications","useCatalogApi","useGetCatalogUnfiltered","_useCatalogApi","useGetCatalog","_useCatalogApi2","currentQ","catalog","searchSuggestions","proxy","getMyLocation","locationSuggestions","onLocationAutocompleteSelect","distance","search","locationLoading","municipalities","municipalitiesData","m","Kunta","Maakunta","OPENSTREETMAP_NOMINATIM_BASEURL","DEFAULT_ZOOM","DEFAULT_GEOPOINT","DISTANCE_AND_ZOOM_PAIRS","getAddressByCoordinates","geoPoint","data","ok","county","getCoordinatesByAddress","parseFloat","isNaN","getLocationSuggestions","input","municipality","toLowerCase","keywordElement","distanceLearning","navigator","geolocation","getCurrentPosition","pos","coords","latitude","longitude","emit","timeout","_keywordElement$value","focus","initialSearchSuggestions","suggestion","_keyword$value","distancelearning","eopisto","classification","classifications","LanderSearch","Categories","_useGetCatalogUnfilte","getCatalogHasError","_catalog$value","orderBy","_useErrorToast","onBeforeUnmount","hasErrorNow","hadErrorBefore","apiConfiguration","useTenantApi","formatUrl","useListTenants","_useTenantApi","tenant","facebook","twitter","instagram","linkedin","homepage","root","proto","protocol","host","hostname","port","changeConfigurationTenantApi","changeConfigurationCourseApi","changeConfigurationCatalogApi","changeConfigurations","$i18n","locale","Semester","DistanceLearning","courseCount","languages","semester","serviceProviders","weekdays","showMap","zoom","generateQuery","serviceProvider","_step3","_iterator3","dateRangeForSemester","trimEnd","_defineProperty","CurrentYearAutumn","CurrentYearSpring","CurrentYearSummer","NextYearAutumn","NextYearSpring","NextYearSummer","isNumeric","test","useSearch","geocodingState","$route","route","split","serviceproviders","Number","immediate","getCourseLink","background","color","imageUrl","objectFit","expanded","nativeOn","decodedName","useRouter","pushRoute","_ref$keyword","_ref$location","_ref$distance","_ref$weekdays","_ref$semester","_ref$languages","_ref$classifications","_ref$serviceProviders","_ref$distanceLearning","_ref$page","p","goToFrontPage","goToCourse","DEFAULT_COLOR","DEFAULT_IMAGE","luokittelemattomatImage","educationSectorMappings","liikuntaImage","kadentaidotImage","musiikkiImage","kieletImage","kuvataideImage","tanssiImage","tietotekniikkaImage","ruokaImage","terveysImage","kirjallisuusImage","opetusImage","historiaImage","sosiaaliImage","tietoImage","puutarhaImage","kotitalousImage","yleissivistäväImage","kulttuuriImage","perusopetusImage","yhteiskunnallinenImage","luontoImage","ajoneuvoImage","humanistinenImage","vapaaaikaImage","poliisiImage","viestintäImage","liiketalousImage","kansalaisImage","tektiiliImage","VClamp","_props$course3","_props$course4","_props$course5","_useRouter","educationSectorId","item","educationSectorMapping","decode","_item$keywords","CourseCard","distanceLearningList","weekdaysList","semestersList","classificationsList","serviceProvidersList","selected","searchValue","optionClicked","selectedName","option","initialSelection","options","previous","filteredOptions","_props$options","toUpperCase","showSelectedOptionSeparately","getSelectedName","o","clickId","cur","getSemestersList","month","SearchFilterDropdown","_props$semester","selectedSemester","_props$catalog","capitalize","_props$catalog2","_props$catalog3","True","False","preventDefault","newKeyword","newLocation","newDistance","_props$distance","_props$distance2","searchModalActive","index","markers","getIcon","courseId","LPopup","Vue2LeafletMarkerCluster","_props$courses","filteredData","_course$location","markerData","_course$location2","_course$location3","totalNumberOfCourses","perPage","prevIcon","nextIcon","currentPage","pushPage","directives","rawName","number","total","logo","postalcode","phone","email","browseLink","detailsText","_props$tenant","_props$tenant2","match","CourseList","SearchFilters","SearchHeaderDesktop","SearchHeaderMobile","SearchMap","SearchPagination","TenantDropdown","COURSES_ON_PAGE","_useGetCatalog","_useListTenants","tenants","_useListCourses","listCoursesResponse","listCoursesState","listCoursesIsLoading","listCoursesHasError","_useSearch","geocodingIsLoading","geocodingHasError","_tenants$value","te","_serviceProviders$val","listTenantsHasError","current","filteredTenants","Vue","use","VueRouter","routes","redirect","Language","children","Index","Search","ServiceProviders","Course","NotFound","getRouter","r","mode","scrollBehavior","y","beforeEach","to","from","previousRoute","_r$previousRoute","back","initializeI18n","VueI18n","fallbackLocale","numberFormats","fi","sv","en","dateTimeFormats","weekdayShort","weekdayLong","silentFallbackWarn","go","Buefy","Meta","VueCompositionApi","config","productionTip","i18n","h","App","$mount","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","exports","module","loaded","__webpack_modules__","deferred","O","result","chunkIds","priority","notFulfilled","Infinity","i","fulfilled","j","every","splice","getter","__esModule","d","a","definition","defineProperty","enumerable","g","globalThis","Function","obj","prop","prototype","hasOwnProperty","Symbol","toStringTag","nmd","paths","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","chunkLoadingGlobal","self","forEach","__webpack_exports__"],"sourceRoot":""}