يسرني أن أعلن أن كلاً من @祁同伟 و @nathank قد تقدما لرعاية العمل الخاص بتحديد موقع المستخدم عبر عنوان IP
سيكون هذا العمل تجريبيًا لبعض الوقت، ولكني سعيد أيضًا بإخبارك بأن طلب السحب (PR) موجود بالفعل هنا:
main ← automated_ip_based_user_location_determination
opened 02:16PM - 31 Jan 26 UTC
## IP‑based User Location (MaxMind → GeoNames)
### What this adds
- Auto… matically determines a user’s location from their IP after post creation.
- Uses **MaxMind (DiscourseIpInfo)** for identity + GeoNames for canonical lat/lon.
- Stores exactly **one granularity level** per user (`country` / `province` / `city`) in `UserCustomField`
`geo_location`.
- Ensures lat/lon match the chosen granularity (privacy‑correct coordinates).
- Caches GeoNames lookups by `geoname_id` (no extra gems; uses `FinalDestination::HTTP`).
---
## Prerequisites (official accounts)
You must have valid accounts and credentials from:
- **MaxMind GeoLite2**
Sign up and obtain an Account ID + License Key:
https://www.maxmind.com/en/geolite2/signup
- **GeoNames**
Create a username for the GeoNames API and **enable Web Services** in your GeoNames account settings:
https://www.geonames.org/login
---
## Required Configuration
**Env vars (MaxMind)**
- `DISCOURSE_MAXMIND_ACCOUNT_ID`
- `DISCOURSE_MAXMIND_LICENSE_KEY`
**Site settings**
- `location_geonames_username` (GeoNames username)
**Dev note (MaxMind DBs)**
- In development, ensure the MaxMind DBs are downloaded:
DISCOURSE_MAXMIND_ACCOUNT_ID=... DISCOURSE_MAXMIND_LICENSE_KEY=... bundle exec rake maxminddb:get
Restart web/sidekiq afterward so `DiscourseIpInfo` reloads the DBs.
---
## Settings
| Setting | Default | Description |
|---|---:|---|
| `location_ip_granularity` | `city` | Controls stored level: `country`, `province` (admin1), or `city`. |
| `location_geonames_username` | `""` | GeoNames username for `getJSON` requests. Acts as a feature flag
(blank => skip). |
| `location_ip_lookup_cooldown_days` | `1` | Per‑user cooldown between IP lookups (0 disables cooldown). |
| `locations_skip_ip_based_location_update_if_existing` | `true` | Skip IP lookup when existing
`geo_location` already has **lat + lon**. |
| `location_ip_auto_lookup_enabled` | `false` | Auto‑enqueue IP lookups on post creation. Rake task still
works when off. |
---
## Flow
- `post_created` → enqueue `Jobs::Locations::IpLocationLookup` with user ID + IP.
- Job:
- Guards: plugin enabled, users map enabled, GeoNames username present, MaxMind env vars present, cooldown
OK, and optional “existing location” check.
- Uses `DiscourseIpInfo.get(ip)` to get `geoname_ids`.
- Resolves GeoNames IDs, picks feature by granularity, builds `geo_location`.
- Saves `geo_location` to user custom field + updates `locations_user` table.
---
## Job + Hook
**Hook**
- `post_created` now enqueues `Jobs::Locations::IpLocationLookup`
- In development, IP is overridden to a fixed test IP (`2.139.231.7`) to ensure resolvable data.
**Job**
- `Jobs::Locations::IpLocationLookup` (new, in `app/jobs/regular/locations/ip_location_lookup.rb`)
- Logs key steps, skips when prerequisites are missing.
- Writes `geo_location` only when successfully built.
---
## GeoNames Helpers
New modules in `lib/locations/`:
- `GeoNamesClient`
- Calls `https://secure.geonames.org/getJSON` via `FinalDestination::HTTP`.
- Normalizes `geoname_id`, `fcl`, `fcode`, `lat`, `lon`, etc.
- Caches only successful lookups (avoids caching nil).
- `GeoNamesGranularityPicker`
- Selects best `PCLI` / `ADM1` / `PPL*` by desired granularity.
- `GeoLocationBuilder`
- Builds `geo_location` hash with correct `lat/lon`, `state`/`city` based on granularity.
---
## Rake Task
New rake task in `lib/tasks/locations.rake`:
**Task**
rake locations:enqueue_user_ip_location_lookups[username_pattern,pattern_type,delay]
**Behavior**
- Iterates users and enqueues the IP lookup job using `user.ip_address`.
- Progress is based on **matched population** (not total users).
- Skips enqueue when IP is blank.
**Options**
- `username_pattern` (optional): filter users by username.
- `pattern_type`: `string` (default substring match) or `regex`.
- `delay`: seconds between enqueues (float, default `0`).
**Help**
rake locations:enqueue_user_ip_location_lookups:help
هذا ليس مجرد بحث بسيط، نحن نفعل أكثر من ذلك - سيتيح لك هذا تحديد درجة دقة معينة (على سبيل المثال، المدينة) لجميع المواقع المحددة تلقائيًا لحماية خصوصية المستخدم مع زيادة ثقة المجتمع.
(نعم، ستكون هناك بعض المشاكل مع شبكات VPN وأخشى أنه لا يمكننا التغلب على ذلك بسهولة).
بمجرد أن أقتنع بأن هذا يعمل بشكل جيد بما فيه الكفاية، سأقوم بدمجه.
إنه يقع خلف علامة ميزة (feature flag) على أي حال.
سأبقيك على اطلاع، ولكنها أوقات مثيرة، فهذه واحدة من أفضل الإضافات إلى المواقع (Locations) التي ربما حصلنا عليها منذ فترة.
شكراً مرة أخرى لـ @ @祁同伟 و @nathank !!
ونعم، ستكون هناك أيضًا مهمة rake للقيام بذلك لجميع المستخدمين الحاليين …
9 إعجابات