Skip to content

Commit

Permalink
Add local api setup and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
steffenkleinle committed Jan 8, 2025
1 parent 1bd9c72 commit a6f4c3e
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 28 deletions.
6 changes: 4 additions & 2 deletions .env.dev
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
DEVELOPMENT=true
GRUENE_API_URL=http://127.0.0.1:5000

OIDC_CLIENT_ID=gruene_app
OIDC_ISSUER=https://saml.gruene.de/realms/gruene-app-test
USE_LOGIN=true
OIDC_ISSUER=http://127.0.0.1:8080/realms/dev

MAP_MAPLIBRE_URL=assets/maps/gruene_map.json
MAP_ADDRESSSEARCH_URL=https://maps.gruene.verdigado.net/nominatim
5 changes: 3 additions & 2 deletions .env.prod
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
DEVELOPMENT=false
GRUENE_API_URL=https://api.gruene.de

OIDC_CLIENT_ID=gruene_app
OIDC_ISSUER=https://saml.gruene.de/realms/gruenes-netz
USE_LOGIN=true

MAP_MAPLIBRE_URL=assets/maps/gruene_map.json
MAP_ADDRESSSEARCH_URL=https://maps.gruene.verdigado.net/nominatim
GRUENES_NETZ_API_URL=https://api.gruene.de
9 changes: 9 additions & 0 deletions .env.staging
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
DEVELOPMENT=false
GRUENE_API_URL=https://api.gruene.de
GRUENE_API_ACCESS_TOKEN=<access-token>

OIDC_CLIENT_ID=gruene_app
OIDC_ISSUER=https://saml.gruene.de/realms/gruene-app-test

MAP_MAPLIBRE_URL=https://maps.gruene.verdigado.net/styles/wkapp/style.json
MAP_ADDRESSSEARCH_URL=https://nominatim.maps.tuerantuer.org/nominatim
53 changes: 43 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,67 @@

### Initial Setup

1. Install the Android SDK via the [Android plugin](https://www.jetbrains.com/help/idea/create-your-first-android-application.html#754fd) or Android Studio
1. Install the Android SDK via
the [Android plugin](https://www.jetbrains.com/help/idea/create-your-first-android-application.html#754fd) or Android
Studio
2. Install [fvm](https://fvm.app/documentation/getting-started/installation) (flutter version manager)
3. Install flutter

``` shell
fvm install
```
4. Configure local environment
``` shell
cp .env.dev .env
```
5. [Optional] Adjust the environment variables in `.env` as needed
6. [Optional] Open IntelliJ settings and

4. [Optional] Open IntelliJ settings and
- Install the Android plugin and set the Android SDK path
- Install the Dart plugin and set the Dart SDK path
- Install the Flutter plugin and set the Flutter SDK path

#### API Setup

There are two options to connect your app to the Grüne API for development:

- [Connect to the staging Grüne API using an access token](#staging-grüne-api-setup)
- [Connect to the locally running Grüne API](#local-grüne-api-setup)

##### Staging Grüne API Setup

1. Generate an access token for the staging Grüne API
2. Copy staging environment

``` shell
cp .env.staging .env
```

3. Add your `GRUENE_API_ACCESS_TOKEN` to `.env`

##### Local Grüne API Setup

0. Make sure the Grüne API is setup and running. For documentation on the necessary steps, refer to
the [Grüne API README](https://github.com/verdigado/gruene-api).
1. Configure local environment

``` shell
cp .env.dev .env
```

### Run the App

1. Update translations

``` shell
fvm dart run slang
```

2. Run build runner to update API definitions

``` shell
fvm dart run build_runner build
```
3. Run the app (`development`)

### Connecting to local Grüne API
3. [Optional] If you are running the app on a real device and use a local Grüne API, you need to expose the ports:

``` shell
adb reverse tcp:8080 tcp:8080 && adb reverse tcp:5000 tcp:5000
```

TODO
4. Run the app (`development`)
2 changes: 2 additions & 0 deletions android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- this setting allows using local keycloak and api instances via non-https connection in development -->
<application android:usesCleartextTraffic="true"/>
</manifest>
3 changes: 3 additions & 0 deletions lib/app/auth/repository/auth_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class AuthRepository {
AuthorizationTokenRequest(
Config.oidcClientId,
Config.oidcCallbackPath,
allowInsecureConnections: Config.development,
issuer: Config.oidcIssuer,
scopes: ['openid', 'profile', 'email', 'offline_access'],
),
Expand All @@ -43,6 +44,7 @@ class AuthRepository {
idTokenHint: idToken,
postLogoutRedirectUrl: Config.oidcCallbackPath,
discoveryUrl: '${Config.oidcIssuer}/.well-known/openid-configuration',
allowInsecureConnections: Config.development,
),
);

Expand All @@ -69,6 +71,7 @@ class AuthRepository {
TokenRequest(
Config.oidcClientId,
Config.oidcCallbackPath,
allowInsecureConnections: Config.development,
refreshToken: refreshToken,
issuer: Config.oidcIssuer,
),
Expand Down
17 changes: 10 additions & 7 deletions lib/app/constants/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import 'package:flutter_dotenv/flutter_dotenv.dart';

class Config {
static String get appId => 'de.gruene.wkapp';
static bool get development => bool.parse(dotenv.env['DEVELOPMENT']!);

static String get grueneApiUrl => dotenv.env['GRUENE_API_URL']!;
static String get grueneApiAccessToken => dotenv.env['GRUENE_API_ACCESS_TOKEN'] ?? '';

static String get oidcCallbackPath => '${Config.appId}://oauthredirect';
static String get oidcClientId => dotenv.env['OIDC_CLIENT_ID'] ?? '';
static String get oidcIssuer => dotenv.env['OIDC_ISSUER'] ?? '';
static bool get useLogin => dotenv.env['USE_LOGIN'] == 'true';
static String get maplibreUrl => dotenv.env['MAP_MAPLIBRE_URL'] ?? '';
static String get addressSearchUrl => dotenv.env['MAP_ADDRESSSEARCH_URL'] ?? '';
static String get gruenesNetzApiUrl => dotenv.env['GRUENES_NETZ_API_URL'] ?? 'http://localhost:5000';
static String get gruenesNetzAccessToken => dotenv.env['GRUENES_NETZ_ACCESS_TOKEN'] ?? '';
static String get oidcClientId => dotenv.env['OIDC_CLIENT_ID']!;
static String get oidcIssuer => dotenv.env['OIDC_ISSUER']!;

static String get maplibreUrl => dotenv.env['MAP_MAPLIBRE_URL']!;
static String get addressSearchUrl => dotenv.env['MAP_ADDRESSSEARCH_URL']!;

static bool get androidFloss {
// may be needed when building for f-droid store
Expand Down
3 changes: 1 addition & 2 deletions lib/app/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:gruene_app/app/auth/bloc/auth_bloc.dart';
import 'package:gruene_app/app/constants/config.dart';
import 'package:gruene_app/app/constants/routes.dart';

GoRouter createAppRouter(BuildContext context) {
Expand All @@ -19,7 +18,7 @@ GoRouter createAppRouter(BuildContext context) {
],
redirect: (context, state) {
final authBloc = context.read<AuthBloc>();
final isLoggedIn = !Config.useLogin || authBloc.state is Authenticated;
final isLoggedIn = authBloc.state is Authenticated;
final isLoggingIn = state.uri.toString() == Routes.login.path;
final isMfa = [
Routes.mfa.path,
Expand Down
6 changes: 3 additions & 3 deletions lib/app/services/gruene_api_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ Future<GrueneApi> createGrueneApiClient() async {
List<chopper.Interceptor> interceptors = [UserAgentInterceptor(userAgentHeaderValue)];
chopper.Authenticator? authenticator;

if (Config.gruenesNetzAccessToken.isNotEmpty) {
interceptors.add(AuthInterceptor.withFixedAccessToken(Config.gruenesNetzAccessToken));
if (Config.grueneApiAccessToken.isNotEmpty) {
interceptors.add(AuthInterceptor.withFixedAccessToken(Config.grueneApiAccessToken));
} else {
AuthRepository repo = AuthRepository();
authenticator = AccessTokenAuthenticator(repo);
interceptors.add(AuthInterceptor.withAuthenticatorRepository(repo));
}

return GrueneApi.create(
baseUrl: Uri.parse(Config.gruenesNetzApiUrl),
baseUrl: Uri.parse(Config.grueneApiUrl),
authenticator: authenticator,
interceptors: interceptors,
);
Expand Down
3 changes: 1 addition & 2 deletions lib/features/settings/screens/settings_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:gruene_app/app/auth/bloc/auth_bloc.dart';
import 'package:gruene_app/app/constants/config.dart';
import 'package:gruene_app/app/constants/routes.dart';
import 'package:gruene_app/app/constants/urls.dart';
import 'package:gruene_app/app/theme/theme.dart';
Expand All @@ -19,7 +18,7 @@ class SettingsScreen extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final authBloc = context.read<AuthBloc>();
final isLoggedIn = !Config.useLogin || authBloc.state is Authenticated;
final isLoggedIn = authBloc.state is Authenticated;
return ListView(
padding: const EdgeInsets.only(top: 32),
children: [
Expand Down

0 comments on commit a6f4c3e

Please sign in to comment.