diff --git a/lib/kosapi_client/entity.rb b/lib/kosapi_client/entity.rb index 34c7ff1..dde508f 100644 --- a/lib/kosapi_client/entity.rb +++ b/lib/kosapi_client/entity.rb @@ -7,6 +7,7 @@ require 'kosapi_client/entity/data_mappings' require 'kosapi_client/entity/base_entity' require 'kosapi_client/entity/result_page' +require 'kosapi_client/entity/coursin' require 'kosapi_client/entity/course_event' require 'kosapi_client/entity/course' require 'kosapi_client/entity/timetable_slot' diff --git a/lib/kosapi_client/entity/coursin.rb b/lib/kosapi_client/entity/coursin.rb new file mode 100644 index 0000000..f0855ac --- /dev/null +++ b/lib/kosapi_client/entity/coursin.rb @@ -0,0 +1,17 @@ +module KOSapiClient + module Entity + class Coursin < BaseEntity + + map_data :capacity + map_data :capacity_overfill, Integer + map_data :course # TODO: fix circular reference. map_data :course, Course + map_data :occupied, Integer + map_data :semester + map_data :tutorial_capacity, Integer + map_data :examiners, [Link], array_wrapper_element: :teacher + map_data :guarantors, [Link], array_wrapper_element: :teacher + map_data :instructors, [Link], array_wrapper_element: :teacher + map_data :lecturers, [Link], array_wrapper_element: :teacher + end + end +end diff --git a/lib/kosapi_client/entity/data_mappings.rb b/lib/kosapi_client/entity/data_mappings.rb index e843466..81e1f46 100644 --- a/lib/kosapi_client/entity/data_mappings.rb +++ b/lib/kosapi_client/entity/data_mappings.rb @@ -66,12 +66,17 @@ def set_mapped_attributes(instance, source_hash) def set_mapped_attribute(instance, name, source_hash, mapping_options) namespace = mapping_options[:namespace] src_element = mapping_options[:element] || name + if namespace key = "#{namespace}_#{src_element}".to_sym else key = src_element end + value = source_hash[key] + + value = value[mapping_options[:array_wrapper_element]] if mapping_options.key? :array_wrapper_element + if value.nil? raise "Missing value for attribute #{name}" if mapping_options[:required] if mapping_options[:type].is_a?(Array) diff --git a/lib/kosapi_client/request_builder.rb b/lib/kosapi_client/request_builder.rb index 2fa046d..8446924 100644 --- a/lib/kosapi_client/request_builder.rb +++ b/lib/kosapi_client/request_builder.rb @@ -19,6 +19,11 @@ def limit(num) self end + def sem(code) + @url_builder.set_query_param(:sem, code) + self + end + def query(params = {}) raise 'Empty parameters to query are not allowed' if params.empty? if params.instance_of?(String) diff --git a/lib/kosapi_client/resource/courses_builder.rb b/lib/kosapi_client/resource/courses_builder.rb index 54854c5..faff6d0 100644 --- a/lib/kosapi_client/resource/courses_builder.rb +++ b/lib/kosapi_client/resource/courses_builder.rb @@ -7,6 +7,61 @@ def detail(level = 1) self end + ### + # GET /courses/{code}/parallels + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/parallels/ + # @link: https://kosapi.fit.cvut.cz/projects/kosapi/wiki/Courses#GET-coursescodeparallels + ## + # Example: + # client.courses.find({course_code}).parallels + # client.courses.find({course_code}).sem({semester_code}).parallels + ### + def parallels + raise 'Call #find before asking for parallels' unless id_set? + url_builder.set_path(id, 'parallels') + self + end + + ### + # GET /courses/{code}/students + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/students/ + # @link: https://kosapi.fit.cvut.cz/projects/kosapi/wiki/Courses#GET-coursescodestudents + ## + # Example: + # client.courses.find({course_code}).students + # client.courses.find({course_code}).sem({semester_code}).students + ### + def students + raise 'Call #find before asking for students' unless id_set? + url_builder.set_path(id, 'students') + self + end + + ### + # GET /courses/{code}/instances + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/instances/ + # @link: https://kosapi.fit.cvut.cz/projects/kosapi/wiki/Courses#GET-coursescodeinstances + ## + # Example: + # client.courses.find({course_code}).instances + ### + def instances + raise 'Call #find before asking for course instances' unless id_set? + url_builder.set_path(id, 'instances') + self + end + + ### + # GET /courses/{code}/instances/{semester} + ### + def instance(semester) + raise 'Call #find before asking for course instance' unless id_set? + url_builder.set_path(id, 'instances', semester) + finalize + end end end end diff --git a/spec/integration/courses_spec.rb b/spec/integration/courses_spec.rb index c6b1cc9..afbfb16 100644 --- a/spec/integration/courses_spec.rb +++ b/spec/integration/courses_spec.rb @@ -25,4 +25,24 @@ expect(page.items).to eq [] end + describe "#parallels" do + it 'returns parallels for course in specified semester' do + parallels = client.courses.find('MI-PAA').sem('B141').parallels.limit(20) + expect(parallels.count).to eq 9 + end + end + + describe "#students" do + it 'returns students of course in specified semester' do + students = client.courses.find('MI-PAA').sem('B141').students.limit(200) + expect(students.count).to eq 188 + end + end + + describe "#instance" do + it 'returns instance for course in specified semester' do + instance = client.courses.find('MI-PAA').instance('B141') + expect(instance).to be_a KOSapiClient::Entity::Coursin + end + end end diff --git a/spec/integration/parallels_spec.rb b/spec/integration/parallels_spec.rb index 35117e4..db1f1dc 100644 --- a/spec/integration/parallels_spec.rb +++ b/spec/integration/parallels_spec.rb @@ -44,7 +44,7 @@ end it 'parses timetable slot ID' do - page = client.parallels + page = client.parallels.query('course.code' => 'MI-PAA') slot = page.items.first.timetable_slots.first expect(slot.id).not_to be_nil end diff --git a/spec/kosapi_client/entity/data_mappings_spec.rb b/spec/kosapi_client/entity/data_mappings_spec.rb index 155cc40..835cd52 100644 --- a/spec/kosapi_client/entity/data_mappings_spec.rb +++ b/spec/kosapi_client/entity/data_mappings_spec.rb @@ -108,6 +108,14 @@ expect(instance.foo).to eq '123' end + it 'supports array wrapping element name configuration' do + dummy_class.map_data :foo, String, array_wrapper_element: :bar + instance = dummy_class.parse(foo: {bar: ['123','456']}) + expect(instance.foo).to be_a Array + expect(instance.foo.count).to eq 2 + expect(instance.foo.first).to eq '123' + end + end describe '#to_hash' do diff --git a/spec/kosapi_client/resource/courses_builder_spec.rb b/spec/kosapi_client/resource/courses_builder_spec.rb index b9de371..5535f0f 100644 --- a/spec/kosapi_client/resource/courses_builder_spec.rb +++ b/spec/kosapi_client/resource/courses_builder_spec.rb @@ -17,4 +17,77 @@ end end + + describe '#students' do + + before { allow(url_builder).to receive(:set_path) } + + it 'throws error when course id not set' do + expect { builder.students }.to raise_error(RuntimeError) + end + + it 'returns self' do + builder.find(42) + expect(builder.students).to eq builder + end + + it 'adds students to URL' do + expect(url_builder).to receive(:set_path).with(42, 'students') + builder.find(42).students + end + end + + describe '#parallels' do + + before { allow(url_builder).to receive(:set_path) } + + it 'throws error when course id not set' do + expect { builder.parallels }.to raise_error(RuntimeError) + end + + it 'returns self' do + builder.find(42) + expect(builder.parallels).to eq builder + end + + it 'adds students to URL' do + expect(url_builder).to receive(:set_path).with(42, 'parallels') + builder.find(42).parallels + end + end + + describe '#instances' do + + before { allow(url_builder).to receive(:set_path) } + + it 'throws error when course id not set' do + expect { builder.instances }.to raise_error(RuntimeError) + end + + it 'returns self' do + builder.find(42) + expect(builder.instances).to eq builder + end + + it 'adds instances to URL' do + expect(url_builder).to receive(:set_path).with(42, 'instances') + builder.find(42).instances + end + end + + describe '#instance' do + + before { allow(url_builder).to receive(:set_path) } + + it 'throws error when course id not set' do + expect { builder.instance('foo') }.to raise_error(RuntimeError) + end + + it 'adds instance to URL' do + expect(url_builder).to receive(:set_path).with(42) + expect(url_builder).to receive(:set_path).with(42, 'instances', 'foo') + builder.find(42).instance('foo') + end + end + end