pincode_finder 0.1.2 → 0.1.4

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: 858a84640a57fedc687e52a9e1fa29e0f85a1b2de9b44096bd74232a8da015a5
4
- data.tar.gz: 34450494e9a7e41b9beaf160f95041d90c3de16b3bf2cf183c4a15a2c25d6111
3
+ metadata.gz: 23b0acc58abe3487875681d61457003462b09264ea4b6044bf67f38e219c2fbd
4
+ data.tar.gz: 942ed9168f3635900da76105d98a41cf28e3c2a2be3c464ee72a52f7ef3754f5
5
5
  SHA512:
6
- metadata.gz: 32b93766384dd4cbff6d6a77f7f0584205f560fed96cb8a59772910a0953cfd3ce167c9fa306010a3656129dc2082bdd213e2cb94e689e3e3937c8f08e4138b4
7
- data.tar.gz: 15725e99cc9a852f23f75a90cc153bfa956ca881927489c464928b430435a3115ec5352014f0469a225b17aadd7c671cb77e6e5f377c8a92cda270ca023f154a
6
+ metadata.gz: 464841f577b1fe42a5668c0be326683b8c9c303152b349f893b3602ce92c935560e0b55f5e97fb77b395ac4ae5e3b03c3fd3597524b63740a1a4851c99897c87
7
+ data.tar.gz: ad92420da504249477cdb6e854ea8c206fcaa713f25cd4a9fdb489073a8c2d6a1249403a68b5fbc8edc06c8c067a9d2587e8b1a1f2943dd8eea9b3f1b502a356
Binary file
@@ -0,0 +1,19 @@
1
+ module PincodeFinder
2
+ class Config
3
+ attr_accessor :github_owner, :github_repo, :github_token
4
+
5
+ def initialize
6
+ @github_owner = nil
7
+ @github_repo = nil
8
+ @github_token = nil
9
+ end
10
+ end
11
+
12
+ def self.config
13
+ @config ||= Config.new
14
+ end
15
+
16
+ def self.configure
17
+ yield(config)
18
+ end
19
+ end
@@ -0,0 +1,64 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "json"
4
+ require "base64"
5
+
6
+ module PincodeFinder
7
+ class GitHubClient
8
+ def initialize
9
+ @owner = PincodeFinder.config.github_owner
10
+ @repo = PincodeFinder.config.github_repo
11
+ @token = PincodeFinder.config.github_token
12
+ @api = "https://api.github.com"
13
+ @file = "pincode_data_optimized.json.gz"
14
+ end
15
+
16
+ def get_file_with_sha
17
+ uri = URI("#{@api}/repos/#{@owner}/#{@repo}/contents/data/#{@file}")
18
+
19
+ req = Net::HTTP::Get.new(uri)
20
+ req["Authorization"] = "token #{@token}"
21
+ req["Accept"] = "application/vnd.github+json"
22
+
23
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
24
+
25
+ return { json: {}, sha: nil } unless res.is_a?(Net::HTTPSuccess)
26
+
27
+ data = JSON.parse(res.body)
28
+ content = Base64.decode64(data["content"])
29
+
30
+ json_string = Zlib::GzipReader.new(StringIO.new(content)).read
31
+
32
+ { json: JSON.parse(json_string), sha: data["sha"] }
33
+ end
34
+
35
+ def update_file(json_data, sha)
36
+ json_string = JSON.pretty_generate(json_data)
37
+
38
+ # compress
39
+ string_io = StringIO.new
40
+ gz = Zlib::GzipWriter.new(string_io)
41
+ gz.write(json_string)
42
+ gz.close
43
+ compressed = string_io.string
44
+
45
+ encoded = Base64.strict_encode64(compressed)
46
+
47
+ uri = URI("#{@api}/repos/#{@owner}/#{@repo}/contents/data/#{@file}")
48
+
49
+ body = {
50
+ message: "Update #{@file}",
51
+ content: encoded,
52
+ sha: sha,
53
+ branch: "main"
54
+ }
55
+
56
+ req = Net::HTTP::Put.new(uri)
57
+ req["Authorization"] = "token #{@token}"
58
+ req["Accept"] = "application/vnd.github+json"
59
+ req.body = body.to_json
60
+
61
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PincodeFinder
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
  end
@@ -1,26 +1,192 @@
1
- # frozen_string_literal: true
2
1
  require "json"
3
- require 'zlib'
4
- require_relative "pincode_finder/version"
2
+ require "net/http"
3
+ require "uri"
4
+ require "fileutils"
5
+ require "zlib"
6
+ require "base64"
5
7
 
6
- module PincodeFinder
7
- class Error < StandardError; end
8
- data_file = File.expand_path('../data/pincode_data.json.gz', __dir__)
8
+ require_relative "pincode_finder/config"
9
+ require_relative "pincode_finder/github_client"
9
10
 
10
- DATA = Zlib::GzipReader.open(data_file) do |gz|
11
- JSON.parse(gz.read)
12
- end
11
+ module PincodeFinder
12
+ DATA_FILE = File.expand_path("../data/pincode_data_optimized.json.gz", __dir__)
13
+ DETAILS_HASH = "{ district: <district>, state: <state>}".freeze
13
14
 
14
15
  def self.find(pincode)
15
- result = DATA.find { |entry| entry["pincode"].to_s == pincode.to_s }
16
- if result
16
+ pincode = pincode.to_s
17
+ data = load_data
18
+
19
+ record = data[pincode]
20
+
21
+ if record
17
22
  {
18
- pincode: result["pincode"],
19
- district: result["district"],
20
- state: result["state"]
23
+ pincode: pincode,
24
+ state: record["state"],
25
+ district: record["district"],
26
+ verified: record["verified"] || true
21
27
  }
22
28
  else
23
- { error: "Pincode not found" }
29
+ {
30
+ error: "Pincode not found",
31
+ message: "You can add it using: PincodeFinder.add_pincode(#{pincode}, #{DETAILS_HASH})"
32
+ }
33
+ end
34
+ end
35
+
36
+ def self.add_pincode(pincode, input_details)
37
+ pincode = pincode.to_s
38
+ input_details = normalize_and_filter(input_details)
39
+
40
+ data = load_data
41
+ record = data[pincode]
42
+
43
+ return { status: "failure", error: "Pincode already present in the directory" } unless record.nil?
44
+
45
+ verified, error = validate_pincode(pincode, input_details)
46
+ return { status: "failure", error: error } unless error.nil?
47
+
48
+ data[pincode] = input_details.merge("verified" => verified)
49
+
50
+ save_data(data)
51
+
52
+ sync_to_github(data)
53
+
54
+ {
55
+ status: "success",
56
+ data: data[pincode],
57
+ error: nil
58
+ }
59
+ end
60
+
61
+ def self.validate_pincode(pincode, input_details)
62
+ verified, api_data = verify_pincode(pincode)
63
+ return [false, nil] unless verified
64
+
65
+ status, error = input_details_validation(api_data, input_details)
66
+ return [false, error] unless status
67
+
68
+ [verified, nil]
69
+ end
70
+
71
+ def self.verify_pincode(pincode)
72
+ begin
73
+ uri = URI("https://api.postalpincode.in/pincode/#{pincode}")
74
+
75
+ response = Net::HTTP.start(uri.host, uri.port, use_ssl: true,
76
+ open_timeout: 3, read_timeout: 3) do |http|
77
+ http.get(uri.request_uri)
78
+ end
79
+
80
+ return [false, nil] unless response.is_a?(Net::HTTPSuccess)
81
+
82
+ json = JSON.parse(response.body) rescue nil
83
+ return [false, nil] unless json.is_a?(Array) && json[0].is_a?(Hash)
84
+
85
+ status = json[0]["Status"]
86
+ return [false, nil] unless status == "Success"
87
+
88
+ po = json[0]["PostOffice"]
89
+ return [false, nil] unless po.is_a?(Array) && po[0].is_a?(Hash)
90
+
91
+ details = po[0].slice("Division", "District", "State")
92
+
93
+ [true, details]
94
+ rescue StandardError
95
+ [false, nil]
96
+ end
97
+ end
98
+
99
+ def self.update_pincode(pincode, input_details)
100
+ pincode = pincode.to_s
101
+ input_details = normalize_and_filter(input_details)
102
+ data = load_data
103
+
104
+ record = data[pincode]
105
+ return { status: "failure", error: "pincode not found" } unless record
106
+
107
+ verified, error = validate_pincode(pincode, input_details)
108
+ return { status: "failure", error: error } unless error.nil?
109
+
110
+ data[pincode] = input_details.merge("verified" => verified)
111
+ save_data(data)
112
+ sync_to_github(data)
113
+
114
+ {
115
+ status: "success",
116
+ data: data[pincode],
117
+ error: nil
118
+ }
119
+ end
120
+
121
+ def self.delete_pincode(pincode)
122
+ pincode = pincode.to_s
123
+ data = load_data
124
+
125
+ record = data[pincode]
126
+ return { status: "failure", error: "pincode not found" } unless record
127
+
128
+ data.delete(pincode)
129
+
130
+ save_data(data)
131
+ sync_to_github(data)
132
+
133
+ {
134
+ status: "success",
135
+ data: {},
136
+ error: nil
137
+ }
138
+ end
139
+
140
+ def self.input_details_validation(data, input_details)
141
+ input_state = input_details["state"].to_s.titleize
142
+ input_district = input_details["district"].to_s.titleize
143
+
144
+ api_state = data["State"].to_s.titleize
145
+ api_district = data["District"].to_s.titleize
146
+ api_division = data["Division"].to_s.titleize
147
+
148
+ return [false, "Incorrect state. Allowed: #{api_state}"] unless input_state == api_state
149
+
150
+ unless input_district == api_district || input_district == api_division
151
+ return [
152
+ false,
153
+ "Incorrect district. Allowed: #{api_district} or #{api_division}"
154
+ ]
155
+ end
156
+
157
+ [true, nil]
158
+ end
159
+
160
+ def self.load_data
161
+ Zlib::GzipReader.open(DATA_FILE) { |gz| JSON.parse(gz.read) }
162
+ end
163
+
164
+ def self.save_data(json)
165
+ json_string = JSON.pretty_generate(json)
166
+
167
+ Zlib::GzipWriter.open(DATA_FILE) do |gz|
168
+ gz.write(json_string)
169
+ end
170
+ end
171
+
172
+ def self.normalize_and_filter(input_details)
173
+ input_details
174
+ .transform_keys { |k| k.to_s.downcase }
175
+ .slice("district", "state")
176
+ end
177
+
178
+ def self.sync_to_github(data)
179
+ Thread.new do
180
+ begin
181
+ client = GitHubClient.new
182
+
183
+ remote = client.get_file_with_sha
184
+ sha = remote[:sha]
185
+
186
+ client.update_file(data, sha)
187
+ rescue StandardError
188
+ nil
189
+ end
24
190
  end
25
191
  end
26
192
  end
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pincode_finder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aadhi
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-08-28 00:00:00.000000000 Z
12
- dependencies: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
13
26
  description: This gem takes a pincode as input and returns the associated district
14
27
  and state.
15
28
  email:
@@ -19,14 +32,16 @@ extensions: []
19
32
  extra_rdoc_files: []
20
33
  files:
21
34
  - data/pincode_data.json.gz
35
+ - data/pincode_data_optimized.json.gz
22
36
  - lib/pincode_finder.rb
37
+ - lib/pincode_finder/config.rb
38
+ - lib/pincode_finder/github_client.rb
23
39
  - lib/pincode_finder/version.rb
24
40
  homepage: https://github.com/aadhi-flaerhomes/pincode_finder
25
41
  licenses:
26
42
  - MIT
27
43
  metadata:
28
44
  homepage_uri: https://github.com/aadhi-flaerhomes/pincode_finder
29
- post_install_message:
30
45
  rdoc_options: []
31
46
  require_paths:
32
47
  - lib
@@ -41,8 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
41
56
  - !ruby/object:Gem::Version
42
57
  version: '0'
43
58
  requirements: []
44
- rubygems_version: 3.5.10
45
- signing_key:
59
+ rubygems_version: 3.7.2
46
60
  specification_version: 4
47
61
  summary: A gem to find Indian pincodes.
48
62
  test_files: []