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 +4 -4
- data/data/pincode_data_optimized.json.gz +0 -0
- data/lib/pincode_finder/config.rb +19 -0
- data/lib/pincode_finder/github_client.rb +64 -0
- data/lib/pincode_finder/version.rb +1 -1
- data/lib/pincode_finder.rb +181 -15
- metadata +21 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 23b0acc58abe3487875681d61457003462b09264ea4b6044bf67f38e219c2fbd
|
|
4
|
+
data.tar.gz: 942ed9168f3635900da76105d98a41cf28e3c2a2be3c464ee72a52f7ef3754f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
data/lib/pincode_finder.rb
CHANGED
|
@@ -1,26 +1,192 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
1
|
require "json"
|
|
3
|
-
require
|
|
4
|
-
|
|
2
|
+
require "net/http"
|
|
3
|
+
require "uri"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "zlib"
|
|
6
|
+
require "base64"
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
16
|
-
|
|
16
|
+
pincode = pincode.to_s
|
|
17
|
+
data = load_data
|
|
18
|
+
|
|
19
|
+
record = data[pincode]
|
|
20
|
+
|
|
21
|
+
if record
|
|
17
22
|
{
|
|
18
|
-
pincode:
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
pincode: pincode,
|
|
24
|
+
state: record["state"],
|
|
25
|
+
district: record["district"],
|
|
26
|
+
verified: record["verified"] || true
|
|
21
27
|
}
|
|
22
28
|
else
|
|
23
|
-
{
|
|
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.
|
|
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:
|
|
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.
|
|
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: []
|