pricehubble 0.2.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 708dc6002a8c92bc8cdcebbfd1d580c72d199644f343a650d19d9229dd90e86c
4
- data.tar.gz: 59ea57131a818d6fa7af30743963c9e991b167a9e0d364bae6727dc86d91cd72
3
+ metadata.gz: 6c029e790cdf1ec21949212567077f03271666ca6332a3b84a902a262ae6625e
4
+ data.tar.gz: 3df77cae40f611c456283a23e215a840ce88936748aefb9c729a205c61ebd7d8
5
5
  SHA512:
6
- metadata.gz: b416c6035d36d6266ab6968bd445feb5f964d1af09d9feff852cd998f34d5054ae33962e878fc6d1128ef6e19557154da22372a157f3e492a6bb37b936717dbe
7
- data.tar.gz: 3511f1a0bdad3da7ce4f58214e59cc34b159b8012441df368193bff5b162ff6d799a49c5a0fbd6abd65c09f875c2ea1e7000d9c1a67c85a4fd034f5e3d28dfe0
6
+ metadata.gz: 6421682c63aa011271eca9931587badf8fbf7ad1c64aadbfa9bccef42dd170e68dd3dee5ed9f8e965ee47e2055e0fdca398ed355370bd91c8a28e045fbc26729
7
+ data.tar.gz: ebe7f75db3e959c48074e0c74092ca6a9a94789645aba5051ab1a972fb8be66295092fe1a07f62a680f53c977152724e8aef31ae06e32afc316b47092e46c66f
@@ -0,0 +1,38 @@
1
+ name: Build Documentation
2
+ on:
3
+ repository_dispatch:
4
+ types: [documentation]
5
+
6
+ concurrency:
7
+ group: 'docs'
8
+
9
+ jobs:
10
+ docs:
11
+ name: Build gem documentation
12
+ runs-on: ubuntu-20.04
13
+ timeout-minutes: 5
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+
17
+ - name: Install the correct Ruby version
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: 2.5
21
+ bundler-cache: true
22
+
23
+ - name: Prepare the virtual environment
24
+ uses: hausgold/actions/ci@master
25
+ with:
26
+ clone_token: '${{ secrets.CLONE_TOKEN }}'
27
+ settings: '${{ github.repository }}'
28
+ target: ci/gem-test
29
+
30
+ - name: Build gem documentation
31
+ run: make docs
32
+
33
+ - name: Upload the code coverage report
34
+ run: coverage
35
+
36
+ - name: Add this job to the commit status
37
+ run: commit-status '${{ job.status }}'
38
+ if: always()
@@ -0,0 +1,62 @@
1
+ name: Test
2
+ on:
3
+ push:
4
+ branches:
5
+ - '**'
6
+ schedule:
7
+ - cron: '0 0 * * MON'
8
+
9
+ concurrency:
10
+ group: '${{ github.ref }}'
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ test:
15
+ name: 'Test the gem (Ruby ${{ matrix.ruby }}, Rails ${{ matrix.rails }})'
16
+ runs-on: ubuntu-20.04
17
+ timeout-minutes: 5
18
+ strategy:
19
+ fail-fast: false
20
+ matrix:
21
+ ruby: [2.5, 2.6, 2.7]
22
+ rails: [5.2, '6.0']
23
+ env:
24
+ BUNDLE_GEMFILE: 'gemfiles/rails_${{ matrix.rails }}.gemfile'
25
+ steps:
26
+ - uses: actions/checkout@v2
27
+
28
+ - name: Install the correct Ruby version
29
+ uses: ruby/setup-ruby@v1
30
+ with:
31
+ ruby-version: ${{ matrix.ruby }}
32
+ bundler-cache: true
33
+
34
+ - name: Prepare the virtual environment
35
+ uses: hausgold/actions/ci@master
36
+ with:
37
+ clone_token: '${{ secrets.CLONE_TOKEN }}'
38
+ settings: '${{ github.repository }}'
39
+ target: ci/gem-test
40
+
41
+ - name: Run the gem tests
42
+ run: make test
43
+
44
+ - name: Upload the code coverage report
45
+ run: coverage
46
+
47
+ trigger-docs:
48
+ name: Trigger the documentation upload
49
+ runs-on: ubuntu-20.04
50
+ timeout-minutes: 2
51
+ needs: test
52
+ if: github.ref == 'refs/heads/master'
53
+ steps:
54
+ - name: Prepare the virtual environment
55
+ uses: hausgold/actions/ci@master
56
+ with:
57
+ clone_token: '${{ secrets.CLONE_TOKEN }}'
58
+ settings: '${{ github.repository }}'
59
+ target: ci/noop
60
+
61
+ - name: Trigger the documentation upload
62
+ run: workflow documentation
data/.rubocop.yml CHANGED
@@ -8,7 +8,7 @@ Documentation:
8
8
 
9
9
  AllCops:
10
10
  DisplayCopNames: true
11
- TargetRubyVersion: 2.3
11
+ TargetRubyVersion: 2.5
12
12
  Exclude:
13
13
  - bin/**/*
14
14
  - vendor/**/*
@@ -60,3 +60,8 @@ Rails/SkipsModelValidations:
60
60
  Lint/ShadowingOuterLocalVariable:
61
61
  Exclude:
62
62
  - "doc/**/*"
63
+
64
+ # We stay at 80 characters per line.
65
+ # See: https://rubystyle.guide/#max-line-length
66
+ Metrics/LineLength:
67
+ Max: 80
data/Appraisals CHANGED
@@ -1,25 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise 'rails-4.2' do
4
- gem 'activemodel', '~> 4.2.11'
5
- gem 'activesupport', '~> 4.2.11'
6
- gem 'railties', '~> 4.2.11'
7
- end
8
-
9
- appraise 'rails-5.0' do
10
- gem 'activemodel', '~> 5.0.7'
11
- gem 'activesupport', '~> 5.0.7'
12
- gem 'railties', '~> 5.0.7'
13
- end
14
-
15
- appraise 'rails-5.1' do
16
- gem 'activemodel', '~> 5.1.6'
17
- gem 'activesupport', '~> 5.1.6'
18
- gem 'railties', '~> 5.1.6'
19
- end
20
-
21
3
  appraise 'rails-5.2' do
22
4
  gem 'activemodel', '~> 5.2.2'
23
5
  gem 'activesupport', '~> 5.2.2'
24
6
  gem 'railties', '~> 5.2.2'
25
7
  end
8
+
9
+ appraise 'rails-6.0' do
10
+ gem 'activemodel', '~> 6.0.0'
11
+ gem 'activesupport', '~> 6.0.0'
12
+ gem 'railties', '~> 6.0.0'
13
+ end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ### 0.4.2
2
+
3
+ * Migrated to Github Actions
4
+ * Migrated to our own coverage reporting
5
+ * Added the code statistics to the test process
6
+
7
+ ### 0.4.1
8
+
9
+ * Corrected the GNU Make release target
10
+
11
+ ### 0.4.0
12
+
13
+ * Added initial dossier handling (create, delete, sharing link) (#3)
14
+
15
+ ### 0.3.0
16
+
17
+ * Dropped support for Rails <5.2 (#2)
18
+ * Dropped support for Ruby <2.5 (#2)
19
+ * Updated the faraday gem spec to `~> 1.0` (#2)
20
+
1
21
  ### 0.2.0
2
22
 
3
23
  * Added a configuration for request logging which is enabled by default now
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM hausgold/ruby:2.3
1
+ FROM hausgold/ruby:2.5
2
2
  MAINTAINER Hermann Mayer <hermann.mayer@hausgold.de>
3
3
 
4
4
  # Update system gem
data/Makefile CHANGED
@@ -28,9 +28,9 @@ XARGS ?= xargs
28
28
  # Container binaries
29
29
  BUNDLE ?= bundle
30
30
  APPRAISAL ?= appraisal
31
+ GEM ?= gem
31
32
  RAKE ?= rake
32
33
  YARD ?= yard
33
- RAKE ?= rake
34
34
  RUBOCOP ?= rubocop
35
35
 
36
36
  # Files
@@ -75,16 +75,18 @@ install:
75
75
  # Install the dependencies
76
76
  @$(MKDIR) -p $(VENDOR_DIR)
77
77
  @$(call run-shell,$(BUNDLE) check || $(BUNDLE) install --path $(VENDOR_DIR))
78
+ @$(call run-shell,GEM_HOME=vendor/bundle/ruby/$${RUBY_MAJOR}.0 \
79
+ $(GEM) install bundler -v "~> 1.0")
78
80
  @$(call run-shell,$(BUNDLE) exec $(APPRAISAL) install)
79
81
 
80
- update: install
82
+ update:
81
83
  # Install the dependencies
82
84
  @$(MKDIR) -p $(VENDOR_DIR)
83
85
  @$(call run-shell,$(BUNDLE) exec $(APPRAISAL) update)
84
86
 
85
- test: #install
87
+ test:
86
88
  # Run the whole test suite
87
- @$(call run-shell,$(BUNDLE) exec $(RAKE))
89
+ @$(call run-shell,$(BUNDLE) exec $(RAKE) stats spec)
88
90
 
89
91
  $(TEST_GEMFILES): GEMFILE=$(@:test-%=%)
90
92
  $(TEST_GEMFILES):
@@ -116,34 +118,34 @@ endif
116
118
  clean-images:
117
119
  # Clean build images
118
120
  ifeq ($(MAKE_ENV),docker)
119
- @-$(DOCKER) images | $(GREP) price-hubble \
121
+ @-$(DOCKER) images | $(GREP) pricehubble \
120
122
  | $(AWK) '{ print $$3 }' \
121
123
  | $(XARGS) -rn1 $(DOCKER) rmi -f
122
124
  endif
123
125
 
124
126
  distclean: clean clean-containers clean-images
125
127
 
126
- shell: install
128
+ shell:
127
129
  # Run an interactive shell on the container
128
130
  @$(call run-shell,$(BASH) -i)
129
131
 
130
- shell-irb: install
132
+ shell-irb:
131
133
  # Run an interactive IRB shell on the container
132
134
  @$(call run-shell,bin/console)
133
135
 
134
- docs: install
136
+ docs:
135
137
  # Build the API documentation
136
138
  @$(call run-shell,$(BUNDLE) exec $(YARD) -q && \
137
139
  $(BUNDLE) exec $(YARD) stats --list-undoc --compact)
138
140
 
139
- notes: install
141
+ notes:
140
142
  # Print the code statistics (library and test suite)
141
143
  @$(call run-shell,$(BUNDLE) exec $(RAKE) notes)
142
144
 
143
- stats: install
145
+ stats:
144
146
  # Print all the notes from the code
145
147
  @$(call run-shell,$(BUNDLE) exec $(RAKE) stats)
146
148
 
147
149
  release:
148
150
  # Release a new gem version
149
- @$(RAKE) release
151
+ @$(BUNDLE) exec $(RAKE) release
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  ![PriceHubble](doc/assets/project.svg)
2
2
 
3
- [![Build Status](https://travis-ci.com/hausgold/pricehubble.svg?token=4XcyqxxmkyBSSV3wWRt7&branch=master)](https://travis-ci.com/hausgold/pricehubble)
3
+ [![Continuous Integration](https://github.com/hausgold/pricehubble/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/hausgold/pricehubble/actions/workflows/test.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/pricehubble.svg)](https://badge.fury.io/rb/pricehubble)
5
- [![Maintainability](https://api.codeclimate.com/v1/badges/cd15f59fc84566e4b200/maintainability)](https://codeclimate.com/repos/5da572bd60163201b800c255/maintainability)
6
- [![Test Coverage](https://api.codeclimate.com/v1/badges/cd15f59fc84566e4b200/test_coverage)](https://codeclimate.com/repos/5da572bd60163201b800c255/test_coverage)
7
- [![API docs](https://img.shields.io/badge/docs-API-blue.svg)](https://www.rubydoc.info/gems/pricehubble)
5
+ [![Test Coverage](https://automate-api.hausgold.de/v1/coverage_reports/pricehubble/coverage.svg)](https://knowledge.hausgold.de/coverage)
6
+ [![Test Ratio](https://automate-api.hausgold.de/v1/coverage_reports/pricehubble/ratio.svg)](https://knowledge.hausgold.de/coverage)
7
+ [![API docs](https://automate-api.hausgold.de/v1/coverage_reports/pricehubble/documentation.svg)](https://www.rubydoc.info/gems/pricehubble)
8
8
 
9
9
  This project is dedicated to build a client/API wrapper around the
10
10
  [PriceHubble](https://pricehubble.com) REST API. It follows strictly the
@@ -25,6 +25,7 @@ so feel free to send a pull request.
25
25
  - [Use the PriceHubble::Valuation representation](#use-the-pricehubblevaluation-representation)
26
26
  - [Error Handling](#error-handling-1)
27
27
  - [Advanced Request Examples](#advanced-request-examples)
28
+ - [Dossiers](#dossiers)
28
29
  - [Development](#development)
29
30
  - [Contributing](#contributing)
30
31
 
@@ -370,6 +371,56 @@ end
370
371
  # => +-----------+---------------+-------------+-------------+-------------+
371
372
  ```
372
373
 
374
+ ### Dossiers
375
+
376
+ The pricehubble gem allows you to create and delete dossiers for properties.
377
+ The required property data is equal to the valuation request. Additionally the
378
+ pricehubble gem allows you to create sharing links (permalinks) which will link
379
+ to the dossier dashboard application for customers.
380
+
381
+ **Gotcha!** The API allows to update and search for dossiers. Additionally the
382
+ API supports images and logos for dossiers. The pricehubble gem does not
383
+ support this yet.
384
+
385
+ ```ruby
386
+ # The property to create a dossier for
387
+ apartment = {
388
+ location: {
389
+ address: {
390
+ post_code: '22769',
391
+ city: 'Hamburg',
392
+ street: 'Stresemannstr.',
393
+ house_number: '29'
394
+ }
395
+ },
396
+ property_type: { code: :apartment },
397
+ building_year: 1990,
398
+ living_area: 200
399
+ }
400
+
401
+ dossier = PriceHubble::Dossier.new(
402
+ title: 'Customer Dossier for Stresemannstr. 29',
403
+ description: 'Best apartment in the city',
404
+ deal_type: :sale,
405
+ property: apartment,
406
+ country_code: 'DE',
407
+ asking_sale_price: 600_000 # the minimum price the seller is willing to agree
408
+ # valuation_override_sale_price: '', # overwrite the PH value
409
+ # valuation_override_rent_net: '', # overwrite the PH value
410
+ # valuation_override_rent_gross: '', # overwrite the PH value
411
+ # valuation_override_reason_freetext: '' # explain the visitor why
412
+ )
413
+
414
+ # Save the new dossier
415
+ pp dossier.save!
416
+ pp dossier.id
417
+ # => "25de5429-244e-4584-b58e-b0d7428a2377"
418
+
419
+ # Generate a sharing link for the dossier
420
+ pp dossier.link
421
+ # => "https://dash.pricehubble.com/shared/dossier/eyJ0eXAiOiJ..."
422
+ ```
423
+
373
424
  ## Development
374
425
 
375
426
  After checking out the repo, run `bin/setup` to install dependencies. Then, run
data/Rakefile CHANGED
@@ -54,16 +54,21 @@ end
54
54
 
55
55
  # Configure all code statistics directories
56
56
  vendors = [
57
- [:unshift, 'Clients', 'lib/pricehubble/client'],
58
- [:unshift, 'Entities', 'lib/pricehubble/entity'],
59
- [:unshift, 'Utilities', 'lib/pricehubble/utils'],
60
57
  [:unshift, 'Top-levels', 'lib', %r{lib(/pricehubble)?/[^/]+\.rb$}],
58
+ [:unshift, 'Top-levels specs', 'spec',
59
+ %r{spec/pricehubble(_spec\.rb|/[^/]+\.rb$)}],
61
60
 
61
+ [:unshift, 'Clients', 'lib/pricehubble/client'],
62
62
  [:unshift, 'Clients specs', 'spec/client'],
63
+
64
+ [:unshift, 'Entities', 'lib/pricehubble/entity'],
63
65
  [:unshift, 'Entities specs', 'spec/entity'],
66
+
67
+ [:unshift, 'Utilities', 'lib/pricehubble/utils'],
64
68
  [:unshift, 'Utilities specs', 'spec/utils'],
65
- [:unshift, 'Top-levels specs', 'spec',
66
- %r{spec/pricehubble(_spec\.rb|/[^/]+\.rb$)}]
69
+
70
+ [:unshift, 'Instrumentation', 'lib/pricehubble/instrumentation'],
71
+ [:unshift, 'Core Extensions', 'lib/pricehubble/core_ext']
67
72
  ].reverse
68
73
 
69
74
  vendors.each do |method, type, dir, pattern|
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative './config'
5
+
6
+ # The property to create a dossier for
7
+ apartment = {
8
+ location: {
9
+ address: {
10
+ post_code: '22769',
11
+ city: 'Hamburg',
12
+ street: 'Stresemannstr.',
13
+ house_number: '29'
14
+ }
15
+ },
16
+ property_type: { code: :apartment },
17
+ building_year: 1990,
18
+ living_area: 200
19
+ }
20
+
21
+ dossier = PriceHubble::Dossier.new(
22
+ title: 'Customer Dossier for Stresemannstr. 29',
23
+ description: 'Best apartment in the city',
24
+ deal_type: :sale,
25
+ property: apartment,
26
+ country_code: 'DE',
27
+ asking_sale_price: 600_000 # the minimum price the seller is willing to agree
28
+ # valuation_override_sale_price: '', # overwrite the PH value
29
+ # valuation_override_rent_net: '', # overwrite the PH value
30
+ # valuation_override_rent_gross: '', # overwrite the PH value
31
+ # valuation_override_reason_freetext: '' # explain the visitor why
32
+ )
33
+
34
+ # Save the new dossier
35
+ pp dossier.save!
36
+ pp dossier.id
37
+ # => "25de5429-244e-4584-b58e-b0d7428a2377"
38
+
39
+ # Generate a sharing link for the dossier
40
+ pp dossier.link
41
+ # => "https://dash.pricehubble.com/shared/dossier/eyJ0eXAiOiJ..."
@@ -4,8 +4,8 @@
4
4
 
5
5
  source 'https://rubygems.org'
6
6
 
7
- gem 'activemodel', '~> 5.0.7'
8
- gem 'activesupport', '~> 5.0.7'
9
- gem 'railties', '~> 5.0.7'
7
+ gem 'activemodel', '~> 6.0.0'
8
+ gem 'activesupport', '~> 6.0.0'
9
+ gem 'railties', '~> 6.0.0'
10
10
 
11
11
  gemspec path: '../'
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PriceHubble
4
+ module Client
5
+ # A high level client library for the PriceHubble Dossiers API.
6
+ class Dossiers < Base
7
+ # Create a new dossier.
8
+ #
9
+ # @param entity [PriceHubble::Dossier] the entity to use
10
+ # @param args [Hash{Symbol => Mixed}] additional arguments
11
+ # @return [PriceHubble::Dossier, nil] the PriceHubble dossier,
12
+ # or +nil+ on error
13
+ #
14
+ # rubocop:disable Metrics/MethodLength because thats the bare minimum
15
+ # handling is quite complex
16
+ def create_dossier(entity, **args)
17
+ res = connection.post do |req|
18
+ req.path = '/api/v1/dossiers'
19
+ req.body = entity.attributes.compact
20
+ use_default_context(req, :create_dossier)
21
+ use_authentication(req)
22
+ end
23
+ decision(bang: args.fetch(:bang, false)) do |result|
24
+ result.bang(&bang_entity(entity, res, {}))
25
+ result.good(&assign_entity(entity, res))
26
+ successful?(res)
27
+ end
28
+ end
29
+ # rubocop:enable Metrics/MethodLength
30
+
31
+ # Generates a permalink for the specified dossier which will expire after
32
+ # the set number of days.
33
+ #
34
+ # @param entity [PriceHubble::Dossier] the entity to use
35
+ # @param ttl [ActiveSupport::Duration] the time to live for the new link
36
+ # @param locale [String] the user frontend locale
37
+ # @param args [Hash{Symbol => Mixed}] additional arguments
38
+ #
39
+ # rubocop:disable Metrics/MethodLength because thats the bare minimum
40
+ # rubocop:disable Metrics/AbcSize because the decission
41
+ # handling is quite complex
42
+ def share_dossier(entity, ttl:, locale:, **args)
43
+ res = connection.post do |req|
44
+ req.path = '/api/v1/dossiers/links'
45
+ req.body = {
46
+ dossier_id: entity.id,
47
+ days_to_live: ttl.fdiv(1.day.to_i).ceil,
48
+ country_code: entity.country_code,
49
+ locale: locale
50
+ }
51
+ use_default_context(req, :share_dossier)
52
+ use_authentication(req)
53
+ end
54
+ decision(bang: args.fetch(:bang, false)) do |result|
55
+ result.bang(&bang_entity(entity, res, id: entity.try(:id)))
56
+ result.good { res.body.url }
57
+ successful?(res)
58
+ end
59
+ end
60
+ # rubocop:enable Metrics/MethodLength
61
+ # rubocop:enable Metrics/AbcSize
62
+
63
+ # Delete a dossier entity.
64
+ #
65
+ # @param entity [PriceHubble::Dossier] the entity to delete
66
+ # @param args [Hash{Symbol => Mixed}] additional arguments
67
+ #
68
+ # rubocop:disable Metrics/MethodLength because thats the bare minimum
69
+ # rubocop:disable Metrics/AbcSize because the decission
70
+ # handling is quite complex
71
+ def delete_dossier(entity, **args)
72
+ res = connection.delete do |req|
73
+ req.path = "/api/v1/dossiers/#{entity.id}"
74
+ use_default_context(req, :delete_dossier)
75
+ use_authentication(req)
76
+ end
77
+ decision(bang: args.fetch(:bang, false)) do |result|
78
+ result.bang(&bang_entity(entity, res, id: entity.id))
79
+ result.good(&assign_entity(entity, res) do |assigned_entity|
80
+ assigned_entity.mark_as_destroyed.freeze
81
+ end)
82
+ successful?(res)
83
+ end
84
+ end
85
+ # rubocop:enable Metrics/MethodLength
86
+ # rubocop:enable Metrics/AbcSize
87
+
88
+ # Update a dossier entity.
89
+ #
90
+ # TODO: Implement this.
91
+ #
92
+ # @param entity [PriceHubble::Dossier] the entity to update
93
+ # @param args [Hash{Symbol => Mixed}] additional arguments
94
+ # @return [PriceHubble::Dossier, nil] the entity, or +nil+ on error
95
+ def update_dossier(*)
96
+ # PUT dossiers/<dossier_id>
97
+ raise NotImplementedError
98
+ end
99
+
100
+ # Search for dossier entities.
101
+ #
102
+ # TODO: Implement this.
103
+ #
104
+ # @param criteria [Mixed] the search criteria
105
+ # @param args [Hash{Symbol => Mixed}] additional arguments
106
+ # @return [Array<PriceHubble::Dossier>, nil] the entity,
107
+ # or +nil+ on error
108
+ def search_dossiers(*)
109
+ # POST dossiers/search
110
+ raise NotImplementedError
111
+ end
112
+
113
+ # Generate bang method variants
114
+ bangers :create_dossier, :update_dossier, :delete_dossier,
115
+ :share_dossier, :search_dossiers
116
+ end
117
+ end
118
+ end
@@ -18,7 +18,7 @@ module PriceHubble
18
18
 
19
19
  # By definition empty responses (HTTP status 204)
20
20
  # or actual empty bodies should be an empty hash
21
- body = {} if res[:status] == 204 || res[:body].empty?
21
+ body = {} if res[:status] == 204 || res[:body].blank?
22
22
 
23
23
  # Looks like we have some actual data we can wrap
24
24
  res[:body] = \
@@ -4,6 +4,8 @@ module PriceHubble
4
4
  module Client
5
5
  module Utils
6
6
  # Some helpers to work with responses in a general way.
7
+ #
8
+ # rubocop:disable Metrics/BlockLength because of ActiveSupport::Concern
7
9
  module Response
8
10
  extend ActiveSupport::Concern
9
11
 
@@ -53,8 +55,33 @@ module PriceHubble
53
55
  PriceHubble::RequestError.new(nil, res)
54
56
  end
55
57
  end
58
+
59
+ # Perform the assignment of the response to the given entity. This
60
+ # allows a clean usage of the decision flow control for successful
61
+ # requests. Here comes an example:
62
+ #
63
+ # decision do |result|
64
+ # result.good(&assign_entity(entity, res))
65
+ # end
66
+ #
67
+ # @param entity [Hausgold::BaseEntity] the entity instance to handle
68
+ # @param res [Faraday::Response] the response object
69
+ # @return [Proc] the proc which performs the entity handling
70
+ def assign_entity(entity, res, &block)
71
+ lambda do
72
+ entity.assign_attributes(res.body.to_h)
73
+ entity.send(:changes_applied)
74
+ # We need to call +#changed?+ - the +@mutations_from_database+ is
75
+ # unset and this causes issues on subsequent calls to +#changed?+
76
+ # after a freeze (eg. when deleted)
77
+ entity.changed?
78
+ yield(entity) if block
79
+ entity
80
+ end
81
+ end
56
82
  end
57
83
  end
84
+ # rubocop:enable Metrics/BlockLength
58
85
  end
59
86
  end
60
87
  end
@@ -17,6 +17,7 @@ module PriceHubble
17
17
  include PriceHubble::EntityConcern::Attributes
18
18
  include PriceHubble::EntityConcern::Associations
19
19
  include PriceHubble::EntityConcern::Client
20
+ include PriceHubble::EntityConcern::Persistence
20
21
 
21
22
  # We collect all unknown attributes instead of raising while creating a new
22
23
  # instance. The unknown attributes are wrapped inside a
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PriceHubble
4
+ module EntityConcern
5
+ # Map some of the ActiveRecord::Persistence API methods for an entity
6
+ # instance for good compatibility. See: http://bit.ly/2W1rjfF and
7
+ # http://bit.ly/2ARRFYB
8
+ module Persistence
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ # A simple method to query for the state of the entity instance.
13
+ # Returns +false+ whenever the entity or the changes of it were not yet
14
+ # persisted on the remote application. This is helpful for creating new
15
+ # entities from scratch or checking for persisted updates.
16
+ #
17
+ # @return [Boolean] whenever persisted or not
18
+ def persisted?
19
+ return (new_record? ? false : !changed?) \
20
+ if respond_to? :id
21
+
22
+ false
23
+ end
24
+
25
+ # A simple method to query for the state of the entity instance.
26
+ # Returns +false+ whenever the entity is not yet created on the remote
27
+ # application. This is helpful for creating new entities from scratch.
28
+ #
29
+ # @return [Boolean] whenever persisted or not
30
+ def new_record?
31
+ return id.nil? if respond_to? :id
32
+
33
+ true
34
+ end
35
+
36
+ # Mark the entity instance as destroyed.
37
+ #
38
+ # @return [Hausgold::BaseEntity] the instance itself for method chaining
39
+ def mark_as_destroyed
40
+ @destroyed = true
41
+ self
42
+ end
43
+
44
+ # Returns true if this object has been destroyed, otherwise returns
45
+ # false.
46
+ #
47
+ # @return [Boolean] whenever the entity was destroyed or not
48
+ def destroyed?
49
+ @destroyed == true
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PriceHubble
4
+ # The PriceHubble dossier for a single property.
5
+ #
6
+ # @see https://docs.pricehubble.com/#international-dossier-creation
7
+ class Dossier < BaseEntity
8
+ # Configure the client to use
9
+ client :dossiers
10
+
11
+ # Mapped and tracked attributes
12
+ tracked_attr :id, :deal_type, :property, :country_code,
13
+ :title, :description, :asking_sale_price,
14
+ :valuation_override_sale_price, :valuation_override_rent_net,
15
+ :valuation_override_rent_gross,
16
+ :valuation_override_reason_freetext, :logo, :images
17
+
18
+ # Define attribute types for casting
19
+ typed_attr :deal_type, :enum, values: %i[sale rent]
20
+ typed_attr :country_code, :string_inquirer
21
+
22
+ # Associations
23
+ has_one :property, persist: true, initialize: true
24
+
25
+ # Set some defaults when initialized
26
+ after_initialize do
27
+ self.deal_type ||= :sale
28
+ self.country_code ||= 'DE'
29
+ end
30
+
31
+ # Save the dossier.
32
+ #
33
+ # @param args [Hash{Symbol => Mixed}] additional options
34
+ # @return [Boolean] the result state
35
+ def save(**args)
36
+ # When the current entity is already persisted, we send an update
37
+ if id.present?
38
+ # Skip making requests when the current entity is not dirty
39
+ return true unless changed?
40
+
41
+ # The current entity is dirty, so send an update request
42
+ return client.update_dossier(self, **args)
43
+ end
44
+
45
+ # Otherwise we send a new creation request
46
+ client.create_dossier(self, **args) && true
47
+ end
48
+
49
+ # Deletes the instance at the remote application and freezes this
50
+ # instance to reflect that no changes should be made (since they can't
51
+ # be persisted).
52
+ #
53
+ # @param args [Hash{Symbol => Mixed}] addition settings
54
+ # @return [PriceHubble::Dossier, false] whenever the deletion
55
+ # was successful
56
+ def delete(**args)
57
+ client.delete_dossier(self, **args) || false
58
+ end
59
+ alias destroy delete
60
+
61
+ # Create a new dossier share link.
62
+ #
63
+ # @param ttl [ActiveSupport::Duration] the time to live for the new link
64
+ # @param locale [String] the user frontend locale
65
+ # @param args [Hash{Symbol => Mixed}] additional options
66
+ # @return [String] the new dossier frontend link
67
+ def link(ttl: 365.days, locale: 'de_CH', lang: 'de', **args)
68
+ # Make sure the current dossier is saved before we try to generate a link
69
+ return unless save(**args)
70
+
71
+ # Send a "share dossier" request to the service
72
+ url = client.share_dossier(self, ttl: ttl, locale: locale, **args)
73
+ url += "?lang=#{lang}" if url
74
+ url
75
+ end
76
+
77
+ # Generate bang method variants
78
+ bangers :save, :link, :delete, :destroy
79
+ end
80
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module PriceHubble
4
4
  # The version of the +price-hubble+ gem
5
- VERSION = '0.2.0'
5
+ VERSION = '0.4.2'
6
6
  end
data/lib/pricehubble.rb CHANGED
@@ -40,6 +40,7 @@ module PriceHubble
40
40
  autoload :Location, 'pricehubble/entity/location'
41
41
  autoload :Address, 'pricehubble/entity/address'
42
42
  autoload :Coordinates, 'pricehubble/entity/coordinates'
43
+ autoload :Dossier, 'pricehubble/entity/dossier'
43
44
 
44
45
  # Some general purpose utilities
45
46
  module Utils
@@ -77,6 +78,7 @@ module PriceHubble
77
78
  autoload :Base, 'pricehubble/client/base'
78
79
  autoload :Authentication, 'pricehubble/client/authentication'
79
80
  autoload :Valuation, 'pricehubble/client/valuation'
81
+ autoload :Dossiers, 'pricehubble/client/dossiers'
80
82
  end
81
83
 
82
84
  # Separated features of an entity instance
@@ -85,6 +87,7 @@ module PriceHubble
85
87
  autoload :Attributes, 'pricehubble/entity/concern/attributes'
86
88
  autoload :Associations, 'pricehubble/entity/concern/associations'
87
89
  autoload :Client, 'pricehubble/entity/concern/client'
90
+ autoload :Persistence, 'pricehubble/entity/concern/persistence'
88
91
 
89
92
  # Some custom typed attribute helpers
90
93
  module Attributes
data/pricehubble.gemspec CHANGED
@@ -14,6 +14,8 @@ Gem::Specification.new do |spec|
14
14
  spec.description = 'Ruby client for the PriceHubble REST API'
15
15
  spec.homepage = 'https://github.com/hausgold/pricehubble'
16
16
 
17
+ spec.required_ruby_version = '~> 2.5'
18
+
17
19
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
20
  f.match(%r{^(test|spec|features)/})
19
21
  end
@@ -21,23 +23,23 @@ Gem::Specification.new do |spec|
21
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
24
  spec.require_paths = ['lib']
23
25
 
24
- spec.add_runtime_dependency 'activemodel', '>= 4.2.0'
25
- spec.add_runtime_dependency 'activesupport', '>= 4.2.0'
26
- spec.add_runtime_dependency 'faraday', '~> 0.15'
27
- spec.add_runtime_dependency 'faraday_middleware', '~> 0.12'
26
+ spec.add_runtime_dependency 'activemodel', '>= 5.2.0'
27
+ spec.add_runtime_dependency 'activesupport', '>= 5.2.0'
28
+ spec.add_runtime_dependency 'faraday', '~> 1.0'
29
+ spec.add_runtime_dependency 'faraday_middleware', '~> 1.0'
28
30
  spec.add_runtime_dependency 'recursive-open-struct', '~> 1.1'
29
31
 
30
32
  spec.add_development_dependency 'appraisal'
31
33
  spec.add_development_dependency 'bundler', '>= 1.16', '< 3'
32
34
  spec.add_development_dependency 'factory_bot', '~> 4.11'
33
- spec.add_development_dependency 'railties', '>= 4.2.0'
35
+ spec.add_development_dependency 'railties', '>= 4.2.0', '< 6.1'
34
36
  spec.add_development_dependency 'rake', '~> 10.0'
35
37
  spec.add_development_dependency 'rdoc', '~> 6.1'
36
38
  spec.add_development_dependency 'redcarpet', '~> 3.4'
37
39
  spec.add_development_dependency 'rspec', '~> 3.0'
38
40
  spec.add_development_dependency 'rubocop', '~> 0.63.1'
39
41
  spec.add_development_dependency 'rubocop-rspec', '~> 1.31'
40
- spec.add_development_dependency 'simplecov', '~> 0.15'
42
+ spec.add_development_dependency 'simplecov', '< 0.18'
41
43
  spec.add_development_dependency 'terminal-table', '~> 1.8'
42
44
  spec.add_development_dependency 'timecop', '~> 0.9.1'
43
45
  spec.add_development_dependency 'vcr', '~> 3.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pricehubble
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hermann Mayer
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-22 00:00:00.000000000 Z
11
+ date: 2021-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -16,56 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0
19
+ version: 5.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.0
26
+ version: 5.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 4.2.0
33
+ version: 5.2.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 4.2.0
40
+ version: 5.2.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: faraday
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.15'
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0.15'
54
+ version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: faraday_middleware
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.12'
61
+ version: '1.0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.12'
68
+ version: '1.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: recursive-open-struct
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -135,6 +135,9 @@ dependencies:
135
135
  - - ">="
136
136
  - !ruby/object:Gem::Version
137
137
  version: 4.2.0
138
+ - - "<"
139
+ - !ruby/object:Gem::Version
140
+ version: '6.1'
138
141
  type: :development
139
142
  prerelease: false
140
143
  version_requirements: !ruby/object:Gem::Requirement
@@ -142,6 +145,9 @@ dependencies:
142
145
  - - ">="
143
146
  - !ruby/object:Gem::Version
144
147
  version: 4.2.0
148
+ - - "<"
149
+ - !ruby/object:Gem::Version
150
+ version: '6.1'
145
151
  - !ruby/object:Gem::Dependency
146
152
  name: rake
147
153
  requirement: !ruby/object:Gem::Requirement
@@ -230,16 +236,16 @@ dependencies:
230
236
  name: simplecov
231
237
  requirement: !ruby/object:Gem::Requirement
232
238
  requirements:
233
- - - "~>"
239
+ - - "<"
234
240
  - !ruby/object:Gem::Version
235
- version: '0.15'
241
+ version: '0.18'
236
242
  type: :development
237
243
  prerelease: false
238
244
  version_requirements: !ruby/object:Gem::Requirement
239
245
  requirements:
240
- - - "~>"
246
+ - - "<"
241
247
  - !ruby/object:Gem::Version
242
- version: '0.15'
248
+ version: '0.18'
243
249
  - !ruby/object:Gem::Dependency
244
250
  name: terminal-table
245
251
  requirement: !ruby/object:Gem::Requirement
@@ -332,11 +338,12 @@ extensions: []
332
338
  extra_rdoc_files: []
333
339
  files:
334
340
  - ".editorconfig"
341
+ - ".github/workflows/documentation.yml"
342
+ - ".github/workflows/test.yml"
335
343
  - ".gitignore"
336
344
  - ".rspec"
337
345
  - ".rubocop.yml"
338
346
  - ".simplecov"
339
- - ".travis.yml"
340
347
  - ".yardopts"
341
348
  - Appraisals
342
349
  - CHANGELOG.md
@@ -357,18 +364,18 @@ files:
357
364
  - doc/examples/authentication.rb
358
365
  - doc/examples/complex_property_valuations.rb
359
366
  - doc/examples/config.rb
367
+ - doc/examples/dossiers.rb
360
368
  - doc/examples/property_valuations_errors.rb
361
369
  - doc/examples/simple_property_valuations.rb
362
370
  - docker-compose.yml
363
- - gemfiles/rails_4.2.gemfile
364
- - gemfiles/rails_5.0.gemfile
365
- - gemfiles/rails_5.1.gemfile
366
371
  - gemfiles/rails_5.2.gemfile
372
+ - gemfiles/rails_6.0.gemfile
367
373
  - lib/price_hubble.rb
368
374
  - lib/pricehubble.rb
369
375
  - lib/pricehubble/client.rb
370
376
  - lib/pricehubble/client/authentication.rb
371
377
  - lib/pricehubble/client/base.rb
378
+ - lib/pricehubble/client/dossiers.rb
372
379
  - lib/pricehubble/client/request/data_sanitization.rb
373
380
  - lib/pricehubble/client/request/default_headers.rb
374
381
  - lib/pricehubble/client/response/data_sanitization.rb
@@ -390,7 +397,9 @@ files:
390
397
  - lib/pricehubble/entity/concern/attributes/string_inquirer.rb
391
398
  - lib/pricehubble/entity/concern/callbacks.rb
392
399
  - lib/pricehubble/entity/concern/client.rb
400
+ - lib/pricehubble/entity/concern/persistence.rb
393
401
  - lib/pricehubble/entity/coordinates.rb
402
+ - lib/pricehubble/entity/dossier.rb
394
403
  - lib/pricehubble/entity/location.rb
395
404
  - lib/pricehubble/entity/property.rb
396
405
  - lib/pricehubble/entity/property_conditions.rb
@@ -412,23 +421,23 @@ files:
412
421
  homepage: https://github.com/hausgold/pricehubble
413
422
  licenses: []
414
423
  metadata: {}
415
- post_install_message:
424
+ post_install_message:
416
425
  rdoc_options: []
417
426
  require_paths:
418
427
  - lib
419
428
  required_ruby_version: !ruby/object:Gem::Requirement
420
429
  requirements:
421
- - - ">="
430
+ - - "~>"
422
431
  - !ruby/object:Gem::Version
423
- version: '0'
432
+ version: '2.5'
424
433
  required_rubygems_version: !ruby/object:Gem::Requirement
425
434
  requirements:
426
435
  - - ">="
427
436
  - !ruby/object:Gem::Version
428
437
  version: '0'
429
438
  requirements: []
430
- rubygems_version: 3.0.6
431
- signing_key:
439
+ rubygems_version: 3.2.16
440
+ signing_key:
432
441
  specification_version: 4
433
442
  summary: Ruby client for the PriceHubble REST API
434
443
  test_files: []
data/.travis.yml DELETED
@@ -1,27 +0,0 @@
1
- env:
2
- global:
3
- - CC_TEST_REPORTER_ID=e80bc2fc948962da41f411047330599fe2bdafcc378bd99a1c3bffbfae74c20f
4
-
5
- sudo: false
6
- language: ruby
7
- cache: bundler
8
- rvm:
9
- - 2.6
10
- - 2.5
11
- - 2.4
12
- - 2.3
13
-
14
- gemfile:
15
- - gemfiles/rails_4.2.gemfile
16
- - gemfiles/rails_5.0.gemfile
17
- - gemfiles/rails_5.1.gemfile
18
- - gemfiles/rails_5.2.gemfile
19
-
20
- before_install: gem install bundler
21
- before_script:
22
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
23
- - chmod +x ./cc-test-reporter
24
- - ./cc-test-reporter before-build
25
- script: bundle exec rake
26
- after_script:
27
- - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This file was generated by Appraisal
4
-
5
- source 'https://rubygems.org'
6
-
7
- gem 'activemodel', '~> 4.2.11'
8
- gem 'activesupport', '~> 4.2.11'
9
- gem 'railties', '~> 4.2.11'
10
-
11
- gemspec path: '../'
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This file was generated by Appraisal
4
-
5
- source 'https://rubygems.org'
6
-
7
- gem 'activemodel', '~> 5.1.6'
8
- gem 'activesupport', '~> 5.1.6'
9
- gem 'railties', '~> 5.1.6'
10
-
11
- gemspec path: '../'