Skip to content

Commit

Permalink
feat: use new IPAddress component (#49)
Browse files Browse the repository at this point in the history
* feat: use new IPAddress component

* chore: export

* chore: ts
  • Loading branch information
imorland authored Oct 20, 2024
1 parent 23b5ef5 commit 6eb85aa
Show file tree
Hide file tree
Showing 20 changed files with 272 additions and 222 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
],
"require": {
"php": "^8.0",
"flarum/core": "^1.8.2",
"flarum/core": "^1.8.7",
"guzzlehttp/guzzle": "^7.3"
},
"authors": [
Expand Down
7 changes: 7 additions & 0 deletions js/src/@shims/shims.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ declare module 'flarum/common/models/User' {
canSeeCountry: () => boolean;
}
}

declare module 'flarum/common/components/IPAddress' {
export default interface IPAddress {
ipInfo?: IPInfo;
loadIpInfo: () => void;
}
}
5 changes: 5 additions & 0 deletions js/src/admin/extend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Extend from 'flarum/common/extenders';

import { default as commonExtend } from '../common/extend';

export default [...commonExtend];
1 change: 1 addition & 0 deletions js/src/admin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import app from 'flarum/admin/app';
import GeoipSettingsPage from './components/GeoipSettingsPage';

export * from './components';
export { default as extend } from './extend';

app.initializers.add('fof/geoip', () => {
app.extensionData
Expand Down
3 changes: 3 additions & 0 deletions js/src/common/extend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Extend from 'flarum/common/extenders';

export default [];
97 changes: 63 additions & 34 deletions js/src/forum/components/MapModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { handleCopyIP } from '../helpers/ClipboardHelper';
import LabelValue from 'flarum/common/components/LabelValue';
import type Mithril from 'mithril';
import LoadingIndicator from 'flarum/common/components/LoadingIndicator';
import ItemList from 'flarum/common/utils/ItemList';

interface MapModalAttrs extends IInternalModalAttrs {
ipInfo?: IPInfo;
Expand All @@ -14,31 +15,18 @@ interface MapModalAttrs extends IInternalModalAttrs {

export default class MapModal extends Modal<MapModalAttrs> {
ipInfo: IPInfo | undefined;
ipAddr!: string;

oninit(vnode: Mithril.Vnode<MapModalAttrs, this>) {
super.oninit(vnode);
this.ipInfo = this.attrs.ipInfo;
if (this.ipInfo === undefined) {
this.loadIpInfo();
}
this.ipAddr = this.attrs.ipAddr;
}

className() {
return 'MapModal Modal--medium';
}

loadIpInfo() {
app.store
.find<IPInfo>('ip_info', encodeURIComponent(this.attrs.ipAddr))
.then((ipInfo) => {
this.ipInfo = ipInfo;
m.redraw();
})
.catch((error) => {
console.error('Failed to load IP information from the store', error);
});
}

title() {
return app.translator.trans('fof-geoip.forum.map_modal.title');
}
Expand All @@ -57,33 +45,74 @@ export default class MapModal extends Modal<MapModalAttrs> {
return (
<div className="Modal-body">
<div className="IPDetails">
<LabelValue
label={app.translator.trans('fof-geoip.forum.map_modal.ip_address')}
value={
<span className="clickable-ip" onclick={handleCopyIP(this.attrs.ipAddr)}>
{this.attrs.ipAddr}
</span>
}
/>
{ipInfo.countryCode() && <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.country_code')} value={ipInfo.countryCode()} />}
{ipInfo.zipCode() && <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.zip_code')} value={ipInfo.zipCode()} />}
{ipInfo.isp() && <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.isp')} value={ipInfo.isp()} />}
{ipInfo.organization() && (
<LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.organization')} value={ipInfo.organization()} />
)}
{ipInfo.as() && <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.as')} value={ipInfo.as()} />}
{<LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.mobile')} value={ipInfo.mobile() ? 'yes' : 'no'} />}
{this.dataItems().toArray()}

{ipInfo.threatLevel() && <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.threat_level')} value={ipInfo.threatLevel()} />}
{ipInfo.threatTypes().length > 0 && (
<LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.threat_types')} value={ipInfo.threatTypes().join(', ')} />
)}
{ipInfo.error() && <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.error')} value={ipInfo.error()} />}
</div>
<hr />
<div id="mapContainer">
<ZipCodeMap ipInfo={ipInfo} />
</div>
<div className="IPDetails--map">{this.mapItems().toArray()}</div>
</div>
);
}

dataItems(): ItemList<Mithril.Children> {
const items = new ItemList<Mithril.Children>();

items.add(
'ipAddress',
<LabelValue
label={app.translator.trans('fof-geoip.forum.map_modal.ip_address')}
value={
<span className="clickable-ip" onclick={handleCopyIP(this.ipAddr)}>
{this.ipAddr}
</span>
}
/>,
100
);

if (this.ipInfo) {
this.ipInfo.countryCode?.() &&
items.add(
'countryCode',
<LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.country_code')} value={this.ipInfo.countryCode()} />,
90
);

this.ipInfo.zipCode?.() &&
items.add('zipCode', <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.zip_code')} value={this.ipInfo.zipCode()} />, 80);

this.ipInfo.isp?.() &&
items.add('isp', <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.isp')} value={this.ipInfo.isp()} />, 70);

this.ipInfo.organization?.() &&
items.add(
'organization',
<LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.organization')} value={this.ipInfo.organization()} />,
60
);

this.ipInfo.as?.() && items.add('as', <LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.as')} value={this.ipInfo.as()} />, 50);

items.add(
'mobileNetwork',
<LabelValue label={app.translator.trans('fof-geoip.forum.map_modal.mobile')} value={this.ipInfo.mobile() ? 'yes' : 'no'} />,
40
);
}

return items;
}

mapItems(): ItemList<Mithril.Children> {
const items = new ItemList<Mithril.Children>();

items.add('mapContainer', <ZipCodeMap id="mapContainer" ipInfo={this.ipInfo} />, 100);

return items;
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import app from 'flarum/forum/app';
import Component from 'flarum/common/Component';
import Component, { ComponentAttrs } from 'flarum/common/Component';
import LoadingIndicator from 'flarum/common/components/LoadingIndicator';
// @ts-expect-error
import load from 'external-load';
import type Mithril from 'mithril';
import IPInfo from '../models/IPInfo';

let addedResources = false;
const addResources = async () => {
if (addedResources) return;
const leafletCDN = 'https://unpkg.com/[email protected]/dist/';

await load.css('https://unpkg.com/[email protected]/dist/leaflet.css');
await load.js('https://unpkg.com/[email protected]/dist/leaflet.js');
export interface ZipCodeMapAttrs extends ComponentAttrs {
ipInfo: IPInfo;
}

addedResources = true;
};
export default class ZipCodeMap extends Component<ZipCodeMapAttrs> {
ipInfo!: IPInfo;
loading = false;
map: any;
data: any;
addedResources = false;

export default class ZipCodeMap extends Component {
oninit(vnode) {
oninit(vnode: Mithril.Vnode<ZipCodeMapAttrs, this>) {
super.oninit(vnode);

this.ipInfo = this.attrs.ipInfo;

this.addResources();

this.data = null;

if (this.ipInfo.latitude() && this.ipInfo.longitude()) {
Expand All @@ -30,6 +37,15 @@ export default class ZipCodeMap extends Component {
}
}

async addResources() {
if (this.addedResources) return;

await load.css(leafletCDN + 'leaflet.css');
await load.js(leafletCDN + 'leaflet.js');

this.addedResources = true;
}

view() {
if (this.loading) {
return <LoadingIndicator size="medium" />;
Expand All @@ -42,58 +58,50 @@ export default class ZipCodeMap extends Component {
return <div id="geoip-map" oncreate={this.configMap.bind(this)} />;
}

searchLatLon() {
async searchLatLon() {
if (this.loading) return;

this.loading = true;

return addResources().then(
app
.request({
url: `https://nominatim.openstreetmap.org/reverse`,
method: 'GET',
params: {
lat: this.ipInfo.latitude(),
lon: this.ipInfo.longitude(),
format: 'json',
},
})
.then((data) => {
this.data = data;
this.loading = false;

m.redraw();
})
);
const data = await app.request<any>({
url: `https://nominatim.openstreetmap.org/reverse`,
method: 'GET',
params: {
lat: this.ipInfo.latitude(),
lon: this.ipInfo.longitude(),
format: 'json',
},
});

this.data = data;
this.loading = false;

m.redraw();
}

searchZip() {
async searchZip() {
if (this.loading) return;

this.loading = true;

return addResources().then(
app
.request({
url: `https://nominatim.openstreetmap.org/search`,
method: 'GET',
params: {
q: this.ipInfo.zipCode(),
countrycodes: this.ipInfo.countryCode(),
limit: 1,
format: 'json',
},
})
.then((data) => {
this.data = data[0];
this.loading = false;

m.redraw();
})
);
const data = await app.request<any>({
url: `https://nominatim.openstreetmap.org/search`,
method: 'GET',
params: {
q: this.ipInfo.zipCode(),
countrycodes: this.ipInfo.countryCode(),
limit: 1,
format: 'json',
},
});

this.data = data[0];
this.loading = false;

m.redraw();
}

configMap(vnode) {
configMap(vnode: Mithril.VnodeDOM) {
if (!this.data) return;

const { boundingbox: bounding, display_name: displayName } = this.data;
Expand All @@ -110,13 +118,16 @@ export default class ZipCodeMap extends Component {

const zoomLevel = 5; // Set your preferred zoom level here

// @ts-expect-error
this.map = L.map(vnode.dom).setView([centerLat, centerLon], zoomLevel);

// @ts-expect-error
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(this.map);

// Set a marker at the center of the bounding box
// @ts-expect-error
L.marker([centerLat, centerLon]).addTo(this.map).bindPopup(displayName).openPopup();
}
}
7 changes: 7 additions & 0 deletions js/src/forum/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import MapModal from './MapModal';
import ZipCodeMap from './ZipCodeMap';

export const components = {
MapModal,
ZipCodeMap,
};
10 changes: 7 additions & 3 deletions js/src/forum/extend.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import Extend from 'flarum/common/extenders';
import IPInfo from './models/IPInfo';
import Post from 'flarum/common/models/Post';
import User from 'flarum/common/models/User';

import { default as commonExtend } from '../common/extend';
import Post from 'flarum/common/models/Post';
import IPInfo from './models/IPInfo';

export default [
...commonExtend,

new Extend.Store() //
.add('ip_info', IPInfo),

new Extend.Model(Post) //
.hasOne('ip_info'),
.hasOne<IPInfo>('ip_info'),

new Extend.Model(User) //
.attribute('showIPCountry')
Expand Down
28 changes: 0 additions & 28 deletions js/src/forum/extenders/extendAccessTokensList.tsx

This file was deleted.

Loading

0 comments on commit 6eb85aa

Please sign in to comment.