mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-08-15 15:40:32 +02:00
pretty broken, icons missing, login not working. browser opens though and cams still appear on map
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:oauth2_client/oauth2_client.dart';
|
||||
import 'package:oauth2_client/oauth2_helper.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
/// Handles OAuth 2 PKCE login to OpenStreetMap and exposes
|
||||
/// the stored access token & display name.
|
||||
///
|
||||
/// ─ Requirements ─
|
||||
/// • Register an OAuth app at
|
||||
/// https://www.openstreetmap.org/oauth2/applications
|
||||
/// ‑ Redirect URI: flockmap://auth
|
||||
/// • Put that client ID below (replace 'flockmap').
|
||||
class AuthService {
|
||||
static const _clientId = 'flockmap'; // ← replace with your ID
|
||||
static const _redirect = 'flockmap://auth';
|
||||
|
||||
late final OAuth2Helper _helper;
|
||||
|
||||
String? _displayName; // cached after login
|
||||
String? get displayName => _displayName;
|
||||
|
||||
AuthService() {
|
||||
final client = OAuth2Client(
|
||||
authorizeUrl: 'https://www.openstreetmap.org/oauth2/authorize',
|
||||
tokenUrl: 'https://www.openstreetmap.org/oauth2/token',
|
||||
redirectUri: _redirect,
|
||||
customUriScheme: 'flockmap', // matches redirect scheme
|
||||
);
|
||||
|
||||
_helper = OAuth2Helper(
|
||||
client,
|
||||
clientId: _clientId,
|
||||
scopes: ['write_api'],
|
||||
enablePKCE: true, // PKCE flow
|
||||
// No custom token store needed: oauth2_client will
|
||||
// auto‑use flutter_secure_storage when present.
|
||||
);
|
||||
}
|
||||
|
||||
/* ───────── Public helpers ───────── */
|
||||
|
||||
/// Returns `true` if a non‑expired token is stored.
|
||||
Future<bool> isLoggedIn() async =>
|
||||
(await _helper.getTokenFromStorage())?.isExpired() == false;
|
||||
|
||||
/// Launches browser login if necessary; caches display name.
|
||||
Future<String?> login() async {
|
||||
final token = await _helper.getToken();
|
||||
if (token?.accessToken == null) return null;
|
||||
_displayName = await _fetchUsername(token!.accessToken!);
|
||||
return _displayName;
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
await _helper.removeAllTokens();
|
||||
_displayName = null;
|
||||
}
|
||||
|
||||
/// Safely fetch current access token (or null).
|
||||
Future<String?> getAccessToken() async =>
|
||||
(await _helper.getTokenFromStorage())?.accessToken;
|
||||
|
||||
/* ───────── Internal ───────── */
|
||||
|
||||
Future<String?> _fetchUsername(String accessToken) async {
|
||||
final resp = await http.get(
|
||||
Uri.parse('https://api.openstreetmap.org/api/0.6/user/details.json'),
|
||||
headers: {'Authorization': 'Bearer $accessToken'},
|
||||
);
|
||||
if (resp.statusCode != 200) return null;
|
||||
return jsonDecode(resp.body)['user']?['display_name'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'dart:async';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../models/pending_upload.dart';
|
||||
|
||||
class Uploader {
|
||||
Uploader(this.accessToken, this.onSuccess);
|
||||
|
||||
final String accessToken;
|
||||
final void Function() onSuccess;
|
||||
|
||||
Future<bool> upload(PendingUpload p) async {
|
||||
try {
|
||||
// 1. open changeset
|
||||
final csXml = '''
|
||||
<osm>
|
||||
<changeset>
|
||||
<tag k="created_by" v="FlockMap 0.5"/>
|
||||
<tag k="comment" v="Add surveillance camera"/>
|
||||
</changeset>
|
||||
</osm>''';
|
||||
final csResp = await _post('/api/0.6/changeset/create', csXml);
|
||||
if (csResp.statusCode != 200) return false;
|
||||
final csId = csResp.body;
|
||||
|
||||
// 2. create node
|
||||
final nodeXml = '''
|
||||
<osm>
|
||||
<node changeset="$csId" lat="${p.coord.latitude}" lon="${p.coord.longitude}">
|
||||
<tag k="man_made" v="surveillance"/>
|
||||
<tag k="surveillance:type" v="ALPR"/>
|
||||
<tag k="camera:type" v="fixed"/>
|
||||
<tag k="direction" v="${p.direction.round()}"/>
|
||||
</node>
|
||||
</osm>''';
|
||||
final nodeResp = await _put('/api/0.6/node/create', nodeXml);
|
||||
if (nodeResp.statusCode != 200) return false;
|
||||
|
||||
// 3. close changeset
|
||||
await _put('/api/0.6/changeset/$csId/close', '');
|
||||
|
||||
onSuccess();
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<http.Response> _post(String path, String body) => http.post(
|
||||
Uri.https('api.openstreetmap.org', path),
|
||||
headers: _headers,
|
||||
body: body,
|
||||
);
|
||||
|
||||
Future<http.Response> _put(String path, String body) => http.put(
|
||||
Uri.https('api.openstreetmap.org', path),
|
||||
headers: _headers,
|
||||
body: body,
|
||||
);
|
||||
|
||||
Map<String, String> get _headers => {
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
'Content-Type': 'text/xml',
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user