From 1c05f071276bd4e6ec43e8a3b88bb479a6b01722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pol=C3=ADvka?= Date: Thu, 5 Mar 2015 23:21:51 +0100 Subject: [PATCH 1/3] Extended courses resource. --- lib/kosapi_client/entity.rb | 1 + lib/kosapi_client/entity/coursin.rb | 17 ++++ lib/kosapi_client/entity/data_mappings.rb | 5 ++ lib/kosapi_client/request_builder.rb | 5 ++ lib/kosapi_client/resource/courses_builder.rb | 78 +++++++++++++++++++ spec/integration/courses_spec.rb | 20 +++++ .../entity/data_mappings_spec.rb | 8 ++ .../resource/courses_builder_spec.rb | 73 +++++++++++++++++ 8 files changed, 207 insertions(+) create mode 100644 lib/kosapi_client/entity/coursin.rb 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..68e7032 100644 --- a/lib/kosapi_client/resource/courses_builder.rb +++ b/lib/kosapi_client/resource/courses_builder.rb @@ -7,6 +7,84 @@ def detail(level = 1) self end + ### + # GET /courses/{code}/parallels + # Vrátí paralelky (instance) předmětu + # a) v aktuálním semestru, + # b) ve zvolených semestrech parametrem +sem+, + # c) nebo pro všechny semestry (parametr sem=none). + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/parallels/ + # + # Typ obsahu: Parallel + # Parametry: sem, fields, lang, limit, locEnums, multilang, offset, orderBy, query + # + # @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 + # Vrátí studenty zapsané na (instanci) předmětu + # a) v aktuálním semestru, + # b) ve zvolených semestrech parametrem +sem+, + # c) nebo pro všechny semestry (parametr sem=none). + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/students/ + # + # Typ obsahu: Student + # Parametry: sem, fields, lang, limit, locEnums, multilang, offset, orderBy, query + # + # @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 + # Vrátí všechny instance daného předmětu – pouze atributy instance, nikoli obecné předmětu. + # Ve většině případech budete chtít použít spíše zdroj /courses/{code} s parametrem +sem+. + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/instances/ + # + # Typ obsahu: Coursin + # Proměnné: {code} kód předmětu + # Parametry: fields, lang, multilang, locEnums + # + # @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/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 From 08e35c3f11d0547813f870276d239dee7d0e1fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pol=C3=ADvka?= Date: Thu, 5 Mar 2015 23:21:51 +0100 Subject: [PATCH 2/3] Extended courses resource. --- lib/kosapi_client/entity.rb | 1 + lib/kosapi_client/entity/coursin.rb | 17 ++++ lib/kosapi_client/entity/data_mappings.rb | 5 ++ lib/kosapi_client/request_builder.rb | 5 ++ lib/kosapi_client/resource/courses_builder.rb | 78 +++++++++++++++++++ spec/integration/courses_spec.rb | 20 +++++ .../entity/data_mappings_spec.rb | 8 ++ .../resource/courses_builder_spec.rb | 73 +++++++++++++++++ 8 files changed, 207 insertions(+) create mode 100644 lib/kosapi_client/entity/coursin.rb 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..68e7032 100644 --- a/lib/kosapi_client/resource/courses_builder.rb +++ b/lib/kosapi_client/resource/courses_builder.rb @@ -7,6 +7,84 @@ def detail(level = 1) self end + ### + # GET /courses/{code}/parallels + # Vrátí paralelky (instance) předmětu + # a) v aktuálním semestru, + # b) ve zvolených semestrech parametrem +sem+, + # c) nebo pro všechny semestry (parametr sem=none). + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/parallels/ + # + # Typ obsahu: Parallel + # Parametry: sem, fields, lang, limit, locEnums, multilang, offset, orderBy, query + # + # @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 + # Vrátí studenty zapsané na (instanci) předmětu + # a) v aktuálním semestru, + # b) ve zvolených semestrech parametrem +sem+, + # c) nebo pro všechny semestry (parametr sem=none). + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/students/ + # + # Typ obsahu: Student + # Parametry: sem, fields, lang, limit, locEnums, multilang, offset, orderBy, query + # + # @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 + # Vrátí všechny instance daného předmětu – pouze atributy instance, nikoli obecné předmětu. + # Ve většině případech budete chtít použít spíše zdroj /courses/{code} s parametrem +sem+. + # + # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/instances/ + # + # Typ obsahu: Coursin + # Proměnné: {code} kód předmětu + # Parametry: fields, lang, multilang, locEnums + # + # @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/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 From 7e4c7d95e03e94c3f61ee8cd7419a3e6f96b2062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pol=C3=ADvka?= Date: Sun, 12 Apr 2015 00:15:46 +0200 Subject: [PATCH 3/3] Fixed comments --- lib/kosapi_client/resource/courses_builder.rb | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/lib/kosapi_client/resource/courses_builder.rb b/lib/kosapi_client/resource/courses_builder.rb index 68e7032..faff6d0 100644 --- a/lib/kosapi_client/resource/courses_builder.rb +++ b/lib/kosapi_client/resource/courses_builder.rb @@ -9,16 +9,8 @@ def detail(level = 1) ### # GET /courses/{code}/parallels - # Vrátí paralelky (instance) předmětu - # a) v aktuálním semestru, - # b) ve zvolených semestrech parametrem +sem+, - # c) nebo pro všechny semestry (parametr sem=none). # # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/parallels/ - # - # Typ obsahu: Parallel - # Parametry: sem, fields, lang, limit, locEnums, multilang, offset, orderBy, query - # # @link: https://kosapi.fit.cvut.cz/projects/kosapi/wiki/Courses#GET-coursescodeparallels ## # Example: @@ -33,16 +25,8 @@ def parallels ### # GET /courses/{code}/students - # Vrátí studenty zapsané na (instanci) předmětu - # a) v aktuálním semestru, - # b) ve zvolených semestrech parametrem +sem+, - # c) nebo pro všechny semestry (parametr sem=none). # # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/students/ - # - # Typ obsahu: Student - # Parametry: sem, fields, lang, limit, locEnums, multilang, offset, orderBy, query - # # @link: https://kosapi.fit.cvut.cz/projects/kosapi/wiki/Courses#GET-coursescodestudents ## # Example: @@ -57,15 +41,8 @@ def students ### # GET /courses/{code}/instances - # Vrátí všechny instance daného předmětu – pouze atributy instance, nikoli obecné předmětu. - # Ve většině případech budete chtít použít spíše zdroj /courses/{code} s parametrem +sem+. # # URI: https://kosapi.fit.cvut.cz/api/3/courses/{code}/instances/ - # - # Typ obsahu: Coursin - # Proměnné: {code} kód předmětu - # Parametry: fields, lang, multilang, locEnums - # # @link: https://kosapi.fit.cvut.cz/projects/kosapi/wiki/Courses#GET-coursescodeinstances ## # Example: