pincode_finder 0.1.2 → 0.1.3
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 +141 -16
- metadata +21 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15ab8dc08fdfc82acae07240265686fd24547b4a7240f18ce0d4a6ba339ffaf4
|
|
4
|
+
data.tar.gz: 46c66b6cfae2e16b122be0e1f847de6c950d9396383a85c28ccd9ad85d9f1896
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4eca5b86819d366ab4724e34eb7ed7caa98c12ef3b7f3a8b456d621fd2e51dd3557407408ef09b3ec10033d40bc9292051c5fe4fdf379108404cdfe376cd551a
|
|
7
|
+
data.tar.gz: 711f1b4c664fd00d28a9c74a8b8b3f1aa7e0ff2e552898d6dfcd0284091ec31e45db10137dcd389651bd17fefb0b9625f133bdc9c429f99ba65af3f6101ee1bc
|
|
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,151 @@
|
|
|
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
|
-
|
|
8
|
+
require_relative "pincode_finder/config"
|
|
9
|
+
require_relative "pincode_finder/github_client"
|
|
10
|
+
require "net/http"
|
|
11
|
+
require "uri"
|
|
12
|
+
require "fileutils"
|
|
13
|
+
require "zlib"
|
|
14
|
+
require "base64"
|
|
9
15
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
require_relative "pincode_finder/config"
|
|
17
|
+
require_relative "pincode_finder/github_client"
|
|
18
|
+
|
|
19
|
+
module PincodeFinder
|
|
20
|
+
DATA_FILE = File.expand_path("../data/pincode_data_optimized.json.gz", __dir__)
|
|
21
|
+
DETAILS_HASH = "{ district: <district>, state: <state>}".freeze
|
|
22
|
+
DATA_FILE = File.expand_path("../data/pincode_data_optimized.json.gz", __dir__)
|
|
23
|
+
DETAILS_HASH = "{ district: <district>, state: <state>}".freeze
|
|
13
24
|
|
|
14
25
|
def self.find(pincode)
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
pincode = pincode.to_s
|
|
27
|
+
data = load_data
|
|
28
|
+
|
|
29
|
+
record = data[pincode]
|
|
30
|
+
|
|
31
|
+
if record
|
|
32
|
+
record["pincode"] = pincode
|
|
33
|
+
record
|
|
34
|
+
else
|
|
17
35
|
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
state: result["state"]
|
|
36
|
+
error: "Pincode not found",
|
|
37
|
+
message: "You can add it using: PincodeFinder.add_pincode(#{pincode}, #{DETAILS_HASH})"
|
|
21
38
|
}
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.add_pincode(pincode, input_details)
|
|
43
|
+
pincode = pincode.to_s
|
|
44
|
+
input_details = normalize_and_filter(input_details)
|
|
45
|
+
|
|
46
|
+
verified, api_data = verify_pincode(pincode)
|
|
47
|
+
|
|
48
|
+
if verified
|
|
49
|
+
status, message = input_details_validation(api_data, input_details)
|
|
50
|
+
return { status: "failure", message: message } unless status
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
data = load_data
|
|
54
|
+
|
|
55
|
+
data[pincode] = input_details.merge("verified" => verified)
|
|
56
|
+
|
|
57
|
+
save_data(data)
|
|
58
|
+
|
|
59
|
+
sync_to_github(data)
|
|
60
|
+
|
|
61
|
+
{
|
|
62
|
+
status: "success",
|
|
63
|
+
pincode: pincode,
|
|
64
|
+
details: input_details
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.verify_pincode(pincode)
|
|
69
|
+
begin
|
|
70
|
+
uri = URI("https://api.postalpincode.in/pincode/#{pincode}")
|
|
71
|
+
|
|
72
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true,
|
|
73
|
+
open_timeout: 3, read_timeout: 3) do |http|
|
|
74
|
+
http.get(uri.request_uri)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
return [false, nil] unless response.is_a?(Net::HTTPSuccess)
|
|
78
|
+
|
|
79
|
+
json = JSON.parse(response.body) rescue nil
|
|
80
|
+
return [false, nil] unless json.is_a?(Array) && json[0].is_a?(Hash)
|
|
81
|
+
|
|
82
|
+
status = json[0]["Status"]
|
|
83
|
+
return [false, nil] unless status == "Success"
|
|
84
|
+
|
|
85
|
+
po = json[0]["PostOffice"]
|
|
86
|
+
return [false, nil] unless po.is_a?(Array) && po[0].is_a?(Hash)
|
|
87
|
+
|
|
88
|
+
details = po[0].slice("Division", "District", "State")
|
|
89
|
+
|
|
90
|
+
[true, details]
|
|
91
|
+
rescue StandardError => e
|
|
92
|
+
warn "⚠️ Pincode verification failed: #{e.class} - #{e.message}"
|
|
93
|
+
[false, nil]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.input_details_validation(data, input_details)
|
|
98
|
+
input_state = input_details["state"].to_s.titleize
|
|
99
|
+
input_district = input_details["district"].to_s.titleize
|
|
100
|
+
|
|
101
|
+
api_state = data["State"].to_s.titleize
|
|
102
|
+
api_district = data["District"].to_s.titleize
|
|
103
|
+
api_division = data["Division"].to_s.titleize
|
|
104
|
+
|
|
105
|
+
return [false, "Incorrect state. Allowed: #{api_state}"] unless input_state == api_state
|
|
106
|
+
|
|
107
|
+
unless input_district == api_district || input_district == api_division
|
|
108
|
+
return [
|
|
109
|
+
false,
|
|
110
|
+
"Incorrect district. Allowed: #{api_district} or #{api_division}"
|
|
111
|
+
]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
[true, nil]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def self.load_data
|
|
118
|
+
Zlib::GzipReader.open(DATA_FILE) { |gz| JSON.parse(gz.read) }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def self.save_data(json)
|
|
122
|
+
json_string = JSON.pretty_generate(json)
|
|
123
|
+
|
|
124
|
+
Zlib::GzipWriter.open(DATA_FILE) do |gz|
|
|
125
|
+
gz.write(json_string)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def self.normalize_and_filter(input_details)
|
|
130
|
+
input_details
|
|
131
|
+
.transform_keys { |k| k.to_s.downcase }
|
|
132
|
+
.slice("district", "state")
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def self.sync_to_github(data)
|
|
136
|
+
Thread.new do
|
|
137
|
+
begin
|
|
138
|
+
client = GitHubClient.new
|
|
139
|
+
|
|
140
|
+
remote = client.get_file_with_sha
|
|
141
|
+
sha = remote[:sha]
|
|
142
|
+
|
|
143
|
+
merged = remote[:json].merge(data)
|
|
144
|
+
|
|
145
|
+
client.update_file(merged, sha)
|
|
146
|
+
rescue StandardError
|
|
147
|
+
nil
|
|
148
|
+
end
|
|
24
149
|
end
|
|
25
150
|
end
|
|
26
151
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
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.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aadhi
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2025-11-19 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: base64
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
13
27
|
description: This gem takes a pincode as input and returns the associated district
|
|
14
28
|
and state.
|
|
15
29
|
email:
|
|
@@ -19,7 +33,10 @@ extensions: []
|
|
|
19
33
|
extra_rdoc_files: []
|
|
20
34
|
files:
|
|
21
35
|
- data/pincode_data.json.gz
|
|
36
|
+
- data/pincode_data_optimized.json.gz
|
|
22
37
|
- lib/pincode_finder.rb
|
|
38
|
+
- lib/pincode_finder/config.rb
|
|
39
|
+
- lib/pincode_finder/github_client.rb
|
|
23
40
|
- lib/pincode_finder/version.rb
|
|
24
41
|
homepage: https://github.com/aadhi-flaerhomes/pincode_finder
|
|
25
42
|
licenses:
|
|
@@ -41,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
41
58
|
- !ruby/object:Gem::Version
|
|
42
59
|
version: '0'
|
|
43
60
|
requirements: []
|
|
44
|
-
rubygems_version: 3.
|
|
61
|
+
rubygems_version: 3.4.10
|
|
45
62
|
signing_key:
|
|
46
63
|
specification_version: 4
|
|
47
64
|
summary: A gem to find Indian pincodes.
|