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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 858a84640a57fedc687e52a9e1fa29e0f85a1b2de9b44096bd74232a8da015a5
4
- data.tar.gz: 34450494e9a7e41b9beaf160f95041d90c3de16b3bf2cf183c4a15a2c25d6111
3
+ metadata.gz: 15ab8dc08fdfc82acae07240265686fd24547b4a7240f18ce0d4a6ba339ffaf4
4
+ data.tar.gz: 46c66b6cfae2e16b122be0e1f847de6c950d9396383a85c28ccd9ad85d9f1896
5
5
  SHA512:
6
- metadata.gz: 32b93766384dd4cbff6d6a77f7f0584205f560fed96cb8a59772910a0953cfd3ce167c9fa306010a3656129dc2082bdd213e2cb94e689e3e3937c8f08e4138b4
7
- data.tar.gz: 15725e99cc9a852f23f75a90cc153bfa956ca881927489c464928b430435a3115ec5352014f0469a225b17aadd7c671cb77e6e5f377c8a92cda270ca023f154a
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
@@ -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.3"
5
5
  end
@@ -1,26 +1,151 @@
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"
10
+ require "net/http"
11
+ require "uri"
12
+ require "fileutils"
13
+ require "zlib"
14
+ require "base64"
9
15
 
10
- DATA = Zlib::GzipReader.open(data_file) do |gz|
11
- JSON.parse(gz.read)
12
- end
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
- result = DATA.find { |entry| entry["pincode"].to_s == pincode.to_s }
16
- if result
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
- pincode: result["pincode"],
19
- district: result["district"],
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
- else
23
- { error: "Pincode not found" }
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.2
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: 2024-08-28 00:00:00.000000000 Z
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.5.10
61
+ rubygems_version: 3.4.10
45
62
  signing_key:
46
63
  specification_version: 4
47
64
  summary: A gem to find Indian pincodes.