diff --git a/.circleci/config.yml b/.circleci/config.yml index 0679d7af..c51fcfee 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -83,6 +83,9 @@ commands: - run: command: cp .env.prod .env name: Apply Production Environment + - run: + command: fvm dart run build_runner build + name: Generate Swagger API prepare_workspace: description: Attach the workspace at ~/attached_workspace and list its contents steps: diff --git a/.circleci/src/commands/prepare_project.yml b/.circleci/src/commands/prepare_project.yml index 087165a0..1f1a2220 100644 --- a/.circleci/src/commands/prepare_project.yml +++ b/.circleci/src/commands/prepare_project.yml @@ -1,7 +1,10 @@ -steps: - - run: - name: Generate Translations - command: fvm dart run slang - - run: - name: Apply Production Environment - command: cp .env.prod .env +steps: + - run: + name: Generate Translations + command: fvm dart run slang + - run: + name: Apply Production Environment + command: cp .env.prod .env + - run: + command: fvm dart run build_runner build + name: Generate Swagger API diff --git a/.gitignore b/.gitignore index de3a35ab..81f5ce88 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,7 @@ lib/generated_plugin_registrant.dart .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf +/.idea/caches/deviceStreaming.xml # AWS User-specific .idea/**/aws.xml @@ -204,3 +205,5 @@ devtools_options.yaml .env report.xml node_modules + +/lib/swagger_generated_code/ diff --git a/.idea/misc.xml b/.idea/misc.xml index f4f6d798..964bcb8e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - @@ -6,4 +5,7 @@ + + \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 5f7f0169..4b0defe6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,8 @@ { "FSharp.suggestGitignore": false, "cSpell.words": [ - "gruene" + "gruene", + "housenumber" ], "files.eol": "\n" } \ No newline at end of file diff --git a/README.md b/README.md index c22eeabe..cc5d623a 100644 --- a/README.md +++ b/README.md @@ -38,3 +38,20 @@ The application uses the following environment variables: You can copy the `.env.dev` file to `.env` and fill in the values. Please note that it's not possible to use the OIDC login if issuer url does not have a secure connection. +### Compiling the app + +installing flutter via fvm +`fvm install` + +downloading flutter/dart packages +`fvm flutter pub get` + +#### Creating translation files + +Before building the app, it's needed to generate the translation files + +`fvm flutter dart run slang` + +#### Generate SwaggerAPI Files + +`fvm dart run build_runner build` \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index c43aec85..78997bce 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,7 +1,7 @@ include: package:flutter_lints/flutter.yaml analyzer: - exclude: [build/**] + exclude: [build/**, lib/swagger_generated_code/**] errors: always_use_package_imports: error directives_ordering: error diff --git a/assets/symbols/add_marker.svg b/assets/symbols/add_marker.svg new file mode 100644 index 00000000..c9e77594 --- /dev/null +++ b/assets/symbols/add_marker.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/symbols/posters/poster.png b/assets/symbols/posters/poster.png new file mode 100644 index 00000000..93ef9a87 Binary files /dev/null and b/assets/symbols/posters/poster.png differ diff --git a/assets/symbols/posters/poster_damaged.png b/assets/symbols/posters/poster_damaged.png new file mode 100644 index 00000000..71843634 Binary files /dev/null and b/assets/symbols/posters/poster_damaged.png differ diff --git a/assets/symbols/posters/poster_taken_down.png b/assets/symbols/posters/poster_taken_down.png new file mode 100644 index 00000000..dad832e0 Binary files /dev/null and b/assets/symbols/posters/poster_taken_down.png differ diff --git a/build.yaml b/build.yaml new file mode 100644 index 00000000..16cafd91 --- /dev/null +++ b/build.yaml @@ -0,0 +1,13 @@ +targets: + $default: + sources: + - swaggers/** + builders: + chopper_generator: + options: + header: "// Generated code" + swagger_dart_code_generator: + options: + input_folder: "swaggers/" + output_folder: "lib/swagger_generated_code/" + multipart_file_type: "MultipartFile" \ No newline at end of file diff --git a/lib/app/constants/config.dart b/lib/app/constants/config.dart index 8ab03798..bc3d49e1 100644 --- a/lib/app/constants/config.dart +++ b/lib/app/constants/config.dart @@ -6,4 +6,8 @@ class Config { 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 gruenesNetzApiKey => dotenv.env['GRUENES_NETZ_API_KEY'] ?? ''; } diff --git a/lib/app/geocode/nominatim.dart b/lib/app/geocode/nominatim.dart new file mode 100644 index 00000000..67eec9dd --- /dev/null +++ b/lib/app/geocode/nominatim.dart @@ -0,0 +1,222 @@ +import 'dart:convert'; + +import 'package:gruene_app/app/constants/config.dart'; +import 'package:http/http.dart' as http; + +/// OSM Nominatim helper +class Nominatim { + /// Searches for a place by it's coordinates or OSM object + /// + /// Use either [lat] and [lon] or [osmType] and [osmId], but don't combine + /// them. + /// + /// Using [addressDetails] will include a breakdown of the address into + /// elements. Default is false. + /// + /// Using [extraTags] will include additional information in the result if + /// available, e.g. wikipedia link, opening hours. Default is false. + /// + /// Using [nameDetails] will include a list of alternative names in the + /// results. These may include language variants, references, operator and + /// brand. Default is false. + /// + /// Using [language] will set the preferred language order for showing search + /// results, overrides the value specified in the `Accept-Language` HTTP + /// header if you are running in a browser. Either use a standard RFC2616 + /// accept-language string or a simple comma-separated list of language codes. + /// + /// Using [zoom] will set the level of detail required for the address. + /// This is a number that corresponds roughly to the zoom level used in map + /// frameworks like Leaflet.js, Openlayers etc. In terms of address details + /// the zoom levels are as follows: + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
zoomaddress detail
3country
5state
8county
10city
14suburb
16major streets
17major and minor streets
18building
+ static Future reverseSearch({ + double? lat, + double? lon, + String? osmType, + int? osmId, + bool addressDetails = false, + bool extraTags = false, + bool nameDetails = false, + String? language, + int zoom = 18, + }) async { + final baseServer = Uri.parse(Config.addressSearchUrl); + assert(baseServer.scheme == 'https', 'It\'s required to have the address search on https'); + + final notNullParameters = [lat, lon, osmType, osmId].where((e) => e != null).length; + assert( + notNullParameters == 2, + 'Either provide lat and lon or osmType and osmId', + ); + assert( + (lat != null && lon != null && osmType == null && osmId == null) || + (lat == null && lon == null && osmType != null && osmId != null), + 'Do not mix coordinates and OSM object', + ); + assert( + ['N', 'W', 'R', null].contains(osmType), + 'osmType needs to be one of N, W, R', + ); + assert( + zoom >= 0 && zoom <= 18, + 'Zoom needs to be between 0 and 18', + ); + + final uri = Uri.https( + baseServer.host, + '${baseServer.path}/reverse', + { + 'format': 'jsonv2', + 'zoom': zoom.toString(), + if (lat != null) 'lat': lat.toString(), + if (lon != null) 'lon': lon.toString(), + if (osmType != null) 'osm_type': osmType, + if (osmId != null) 'osm_id': osmId.toString(), + if (addressDetails) 'addressdetails': '1', + if (extraTags) 'extratags': '1', + if (nameDetails) 'namedetails': '1', + if (language != null) 'accept-language': language, + }, + ); + final response = await http.get(uri); + final data = json.decode(response.body) as Map; + if (data['error'] != null) { + throw Exception(data['error']); + } + return Place.fromJson(data); + } +} + +/// A place in the nominatim system +class Place { + // ignore: public_member_api_docs + Place({ + required this.placeId, + required this.osmType, + required this.osmId, + required this.boundingBox, + required this.lat, + required this.lon, + required this.displayName, + required this.placeRank, + required this.category, + required this.type, + required this.importance, + this.icon, + this.address, + this.extraTags, + this.nameDetails, + }); + + // ignore: public_member_api_docs + factory Place.fromJson(Map json) => Place( + placeId: json['place_id'] as int, + osmType: json['osm_type'] != null ? json['osm_type'] as String : null, + osmId: json['osm_id'] != null ? json['osm_id'] as int : null, + boundingBox: (json['boundingbox'] as List).map((e) => e as String).toList(), + lat: double.parse(json['lat'] as String), + lon: double.parse(json['lon'] as String), + displayName: json['display_name'] as String, + placeRank: json['place_rank'] as int, + category: json['category'] as String, + type: json['type'] as String, + importance: json['importance'] is int ? (json['importance'] as int).toDouble() : json['importance'] as double, + icon: json['icon'] != null ? json['icon'] as String : null, + address: json['address'] != null ? json['address'] as Map : null, + extraTags: json['extratags'] != null ? json['extratags'] as Map : null, + nameDetails: json['namedetails'] != null ? json['namedetails'] as Map : null, + ); + + /// Reference to the Nominatim internal database ID + /// See https://nominatim.org/release-docs/latest/api/Output/#place_id-is-not-a-persistent-id + final int placeId; + + /// Reference to the OSM object + final String? osmType; + + /// Reference to the OSM object + final int? osmId; + + /// Area of corner coordinates + /// See https://nominatim.org/release-docs/latest/api/Output/#boundingbox + final List boundingBox; + + /// Latitude of the centroid of the object + final double lat; + + /// Longitude of the centroid of the object + final double lon; + + /// Full comma-separated address + final String displayName; + + /// Search rank of the object + final int placeRank; + + /// Key of the main OSM tag + final String category; + + /// Value of the main OSM tag + final String type; + + /// Computed importance rank + final double importance; + + /// Link to class icon (if available) + final String? icon; + + /// Map of address details + /// Only with [Nominatim.searchByName(addressDetails: true)] + /// See https://nominatim.org/release-docs/latest/api/Output/#addressdetails + final Map? address; + + /// Map with additional useful tags like website or max speed + /// Only with [Nominatim.searchByName(extraTags: true)] + final Map? extraTags; + + /// Map with full list of available names including ref etc. + /// Only with [Nominatim.searchByName(nameDetails: true)] + final Map? nameDetails; +} diff --git a/lib/app/services/gruene_api_campaigns_service.dart b/lib/app/services/gruene_api_campaigns_service.dart new file mode 100644 index 00000000..8616c939 --- /dev/null +++ b/lib/app/services/gruene_api_campaigns_service.dart @@ -0,0 +1,108 @@ +import 'package:chopper/chopper.dart'; +import 'package:gruene_app/app/constants/config.dart'; +import 'package:gruene_app/features/campaigns/models/marker_item_model.dart'; +import 'package:gruene_app/features/campaigns/models/posters/poster_create_model.dart'; +import 'package:gruene_app/swagger_generated_code/gruene_api.swagger.dart'; +import 'package:http/http.dart'; +import 'package:http_parser/http_parser.dart'; +import 'package:intl/intl.dart'; +import 'package:maplibre_gl_platform_interface/maplibre_gl_platform_interface.dart'; + +part 'gruene_api_core.dart'; + +class GrueneApiCampaignsService { + late GrueneApi grueneApi; + + final PoiServiceType poiType; + + GrueneApiCampaignsService({required this.poiType}) { + grueneApi = _GrueneApiCore().getService(); + } + + Future> loadPoisInRegion(LatLng locationSW, LatLng locationNE) async { + final getPoisType = _getPoiGetType(); + final getPoisResult = await grueneApi.v1CampaignsPoisGet( + type: getPoisType, + bbox: [locationSW.latitude, locationSW.longitude, locationNE.latitude, locationNE.longitude].join(','), + ); + return getPoisResult.body!.data.map(_transformToMarkerItem).toList(); + } + + V1CampaignsPoisGetType _getPoiGetType() { + switch (poiType) { + case PoiServiceType.poster: + return V1CampaignsPoisGetType.poster; + case PoiServiceType.door: + return V1CampaignsPoisGetType.house; + case PoiServiceType.flyer: + return V1CampaignsPoisGetType.flyerSpot; + } + } + + CreatePoiType _getPoiCreateType() { + switch (poiType) { + case PoiServiceType.poster: + return CreatePoiType.poster; + case PoiServiceType.door: + return CreatePoiType.house; + case PoiServiceType.flyer: + return CreatePoiType.flyerSpot; + } + } + + MarkerItemModel _transformToMarkerItem(Poi poi) { + final String statusSuffix = _getPosterStatusSuffix(poi.poster!.status); + return MarkerItemModel( + id: int.parse(poi.id), + location: LatLng(poi.coords[0], poi.coords[1]), + status: '${poiType.name}$statusSuffix', + ); + } + + Future createNewPoster(PosterCreateModel newPoster) async { + final requestParam = CreatePoi( + coords: [newPoster.location.latitude, newPoster.location.longitude], + type: _getPoiCreateType(), + address: PoiAddress( + city: newPoster.city!, + zip: newPoster.zipCode!, + street: newPoster.street!, + houseNumber: newPoster.houseNumber!, + ), + ); + // saving POI + final newPoiResponse = await grueneApi.v1CampaignsPoisPost(body: requestParam); + + if (newPoiResponse.error == null && newPoster.photo != null) { + // saving Photo along with POI + var poiId = newPoiResponse.body!.id; + var timeStamp = DateFormat('yyMMdd_HHmmss').format(DateTime.now()); + // ignore: unused_local_variable + final savePoiPhotoResponse = await grueneApi.v1CampaignsPoisPoiIdPhotosPost( + poiId: poiId, + image: MultipartFile.fromBytes( + 'image', + newPoster.photo!, + filename: 'poi_${poiId}_$timeStamp.jpg', + contentType: MediaType('image', 'jpeg'), + ), + ); + } + + return _transformToMarkerItem(newPoiResponse.body!); + } + + String _getPosterStatusSuffix(PoiPosterStatus status) { + switch (status) { + case PoiPosterStatus.damaged: + return '_${status.name}'; + case PoiPosterStatus.removed: + case PoiPosterStatus.missing: + return '_taken_down'; + default: + return ''; + } + } +} + +enum PoiServiceType { poster, door, flyer } diff --git a/lib/app/services/gruene_api_core.dart b/lib/app/services/gruene_api_core.dart new file mode 100644 index 00000000..6621019c --- /dev/null +++ b/lib/app/services/gruene_api_core.dart @@ -0,0 +1,22 @@ +part of 'gruene_api_campaigns_service.dart'; + +class _GrueneApiCore { + late GrueneApi _grueneApiService; + + _GrueneApiCore() { + _grueneApiService = GrueneApi.create( + baseUrl: Uri.parse(Config.gruenesNetzApiUrl), + interceptors: [ + HeadersInterceptor( + { + 'x-api-key': Config.gruenesNetzApiKey, + }, + ), + ], + ); + } + + GrueneApi getService() { + return _grueneApiService; + } +} diff --git a/lib/app/services/nominatim_service.dart b/lib/app/services/nominatim_service.dart new file mode 100644 index 00000000..0e4bd243 --- /dev/null +++ b/lib/app/services/nominatim_service.dart @@ -0,0 +1,31 @@ +import 'package:gruene_app/app/geocode/nominatim.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +class NominatimService { + Future getLocationAddress(LatLng location) async { + final place = await Nominatim.reverseSearch( + lat: location.latitude, + lon: location.longitude, + ); + final address = AddressModel.convertFromPlace(place); + return address; + } +} + +class AddressModel { + final String? street; + final String? city; + final String? zipCode; + final String? houseNumber; + + const AddressModel({this.street, this.houseNumber, this.zipCode, this.city}); + + static AddressModel convertFromPlace(Place place) { + return AddressModel( + street: place.address?['road']?.toString(), + houseNumber: place.address?['house_number']?.toString(), + zipCode: place.address?['postcode']?.toString(), + city: place.address?['city']?.toString(), + ); + } +} diff --git a/lib/app/theme/theme.dart b/lib/app/theme/theme.dart index 57ba7e9f..8e8f1728 100644 --- a/lib/app/theme/theme.dart +++ b/lib/app/theme/theme.dart @@ -77,6 +77,24 @@ class _ThemeTextStyles { color: ThemeColors.text, ), ); + + static TextStyle labelMedium = GoogleFonts.ptSans( + textStyle: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w400, + height: 1.3, + letterSpacing: 0.01, + ), + ); + + static TextStyle labelLarge = GoogleFonts.ptSans( + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + height: 1.3, + letterSpacing: 0.01, + ), + ); } final ThemeData appTheme = ThemeData.light().copyWith( @@ -96,6 +114,8 @@ final ThemeData appTheme = ThemeData.light().copyWith( titleMedium: _ThemeTextStyles.titleMedium, bodyLarge: _ThemeTextStyles.bodyLarge, bodyMedium: _ThemeTextStyles.bodyMedium, + labelLarge: _ThemeTextStyles.labelLarge, + labelMedium: _ThemeTextStyles.labelMedium, labelSmall: _ThemeTextStyles.labelSmall, ), bottomNavigationBarTheme: BottomNavigationBarThemeData( diff --git a/lib/features/campaigns/helper/latlng_extensions.dart b/lib/features/campaigns/helper/latlng_extensions.dart new file mode 100644 index 00000000..1b47bf41 --- /dev/null +++ b/lib/features/campaigns/helper/latlng_extensions.dart @@ -0,0 +1,7 @@ +import 'package:maplibre_gl/maplibre_gl.dart'; + +extension LatLngToString on LatLng { + String toLatLngString() { + return '${latitude.toString()},${longitude.toString()}'; + } +} diff --git a/lib/features/campaigns/helper/marker_item_helper.dart b/lib/features/campaigns/helper/marker_item_helper.dart new file mode 100644 index 00000000..afae2227 --- /dev/null +++ b/lib/features/campaigns/helper/marker_item_helper.dart @@ -0,0 +1,20 @@ +import 'package:gruene_app/features/campaigns/models/marker_item_model.dart'; +import 'package:turf/bbox_polygon.dart'; +import 'package:turf/helpers.dart'; +import 'package:turf/transform.dart'; + +class MarkerItemHelper { + static FeatureCollection transformListToGeoJson(List markerItems) { + return FeatureCollection(features: markerItems.map(transformMarkerItemToGeoJson).toList()); + } + + static Feature transformMarkerItemToGeoJson(MarkerItemModel markerItem) { + return Feature( + id: markerItem.id, + properties: { + 'type': markerItem.status ?? 'poster', + }, + geometry: Point(coordinates: Position(markerItem.location.longitude, markerItem.location.latitude)), + ); + } +} diff --git a/lib/features/campaigns/helper/media_helper.dart b/lib/features/campaigns/helper/media_helper.dart new file mode 100644 index 00000000..e34b59fd --- /dev/null +++ b/lib/features/campaigns/helper/media_helper.dart @@ -0,0 +1,68 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:camerawesome/camerawesome_plugin.dart'; +import 'package:flutter/widgets.dart'; +import 'package:gruene_app/features/campaigns/widgets/app_route.dart'; +import 'package:image/image.dart' as image_lib; + +class MediaHelper { + static const int maxUploadDimension = 1200; + + static Future acquirePhoto(BuildContext context) async { + var image = await Navigator.of(context, rootNavigator: true).push( + AppRoute( + builder: (context) { + return CameraAwesomeBuilder.awesome( + saveConfig: SaveConfig.photo(), + onMediaCaptureEvent: (mediaCapture) async { + if (mediaCapture.status == MediaCaptureStatus.success) { + final imageFile = File(mediaCapture.captureRequest.path!); + Navigator.maybePop(context, imageFile); + } + }, + ); + }, + ), + ); + return image; + } + + static Future resizeAndReduceImage(Uint8List originalImage, ImageType outputType) async { + Uint8List? resizedImg; + + final compressAction = Future.delayed(Duration.zero, () async { + image_lib.Image? img = image_lib.decodeImage(originalImage); + image_lib.Image resized; + if (img!.height > maxUploadDimension || img.width > maxUploadDimension) { + int desiredWidth, desiredHeight; + if (img.width > img.height) { + desiredWidth = maxUploadDimension; + desiredHeight = (img.height / img.width * maxUploadDimension).round(); + } else { + desiredHeight = maxUploadDimension; + desiredWidth = (img.width / img.height * maxUploadDimension).round(); + } + + resized = image_lib.copyResize( + img, + width: desiredWidth, + height: desiredHeight, + maintainAspect: true, + ); + } else { + resized = img; + } + + resizedImg = switch (outputType) { + ImageType.jpeg => Uint8List.fromList(image_lib.encodeJpg(resized, quality: 60)), + ImageType.png => Uint8List.fromList(image_lib.encodePng(resized)) + }; + }); + + await compressAction; + return resizedImg!; + } +} + +enum ImageType { jpeg, png } diff --git a/lib/features/campaigns/helper/util.dart b/lib/features/campaigns/helper/util.dart new file mode 100644 index 00000000..88ac3f0a --- /dev/null +++ b/lib/features/campaigns/helper/util.dart @@ -0,0 +1,9 @@ +import 'package:flutter/services.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +/// Adds an asset image to the currently displayed style +Future addImageFromAsset(MapLibreMapController controller, String name, String assetName) async { + final bytes = await rootBundle.load(assetName); + final list = bytes.buffer.asUint8List(); + return controller.addImage(name, list); +} diff --git a/lib/features/campaigns/models/marker_item_model.dart b/lib/features/campaigns/models/marker_item_model.dart new file mode 100644 index 00000000..20e58181 --- /dev/null +++ b/lib/features/campaigns/models/marker_item_model.dart @@ -0,0 +1,13 @@ +import 'package:maplibre_gl/maplibre_gl.dart'; + +class MarkerItemModel { + final LatLng location; + final int? id; + final String? status; + + const MarkerItemModel({ + this.id, + this.status, + required this.location, + }); +} diff --git a/lib/features/campaigns/models/posters/poster_create_model.dart b/lib/features/campaigns/models/posters/poster_create_model.dart new file mode 100644 index 00000000..9fa0d45a --- /dev/null +++ b/lib/features/campaigns/models/posters/poster_create_model.dart @@ -0,0 +1,21 @@ +import 'dart:typed_data'; + +import 'package:maplibre_gl/maplibre_gl.dart'; + +class PosterCreateModel { + final String? street; + final String? houseNumber; + final String? zipCode; + final String? city; + final LatLng location; + final Uint8List? photo; + + const PosterCreateModel({ + this.street, + this.houseNumber, + this.zipCode, + this.city, + this.photo, + required this.location, + }); +} diff --git a/lib/features/campaigns/screens/poster_add.dart b/lib/features/campaigns/screens/poster_add.dart new file mode 100644 index 00000000..4dd8e96b --- /dev/null +++ b/lib/features/campaigns/screens/poster_add.dart @@ -0,0 +1,236 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:gruene_app/app/services/nominatim_service.dart'; +import 'package:gruene_app/app/theme/theme.dart'; +import 'package:gruene_app/features/campaigns/helper/media_helper.dart'; +import 'package:gruene_app/features/campaigns/models/posters/poster_create_model.dart'; +import 'package:gruene_app/features/campaigns/widgets/textinputfield.dart'; +import 'package:gruene_app/i18n/translations.g.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +class PosterAddScreen extends StatefulWidget { + final LatLng location; + final AddressModel address; + final File? photo; + + const PosterAddScreen({super.key, this.photo, required this.address, required this.location}); + + @override + State createState() => _PostersAddState(); +} + +class _PostersAddState extends State { + TextEditingController streetTextController = TextEditingController(); + TextEditingController houseNumberTextController = TextEditingController(); + TextEditingController zipCodeTextController = TextEditingController(); + TextEditingController cityTextController = TextEditingController(); + File? _currentPhoto; + + @override + void initState() { + streetTextController.text = widget.address.street ?? ''; + houseNumberTextController.text = widget.address.houseNumber ?? ''; + zipCodeTextController.text = widget.address.zipCode ?? ''; + cityTextController.text = widget.address.city ?? ''; + _currentPhoto = widget.photo; + super.initState(); + } + + @override + void dispose() { + streetTextController.dispose(); + houseNumberTextController.dispose(); + zipCodeTextController.dispose(); + cityTextController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Container( + margin: EdgeInsets.all(24), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + children: [ + Expanded( + child: Text( + t.campaigns.posters.addPoster, + style: theme.textTheme.displayMedium, + ), + ), + Container( + alignment: Alignment.centerRight, + width: 50, + height: 50, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: ThemeColors.background, width: 1), + gradient: LinearGradient( + colors: [Color(0xFF03BD4E), Color(0xFF875CFF)], + ), + ), + child: getPhotoPreviewOrIcon(), + ), + ], + ), + Container( + padding: EdgeInsets.symmetric(vertical: 6), + child: Row( + children: [ + Expanded( + child: TextInputField( + textController: streetTextController, + labelText: t.campaigns.address.street, + ), + ), + Container( + padding: EdgeInsets.only(left: 6), + child: TextInputField( + width: 75, + labelText: t.campaigns.address.housenumber, + textController: houseNumberTextController, + ), + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 6), + child: Row( + children: [ + Container( + padding: EdgeInsets.only(right: 6), + child: TextInputField( + width: 75, + labelText: t.campaigns.address.zipcode, + textController: zipCodeTextController, + ), + ), + Expanded( + child: TextInputField( + labelText: t.campaigns.address.city_or_place, + textController: cityTextController, + ), + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 24), + child: Row( + children: [ + Expanded( + child: Container( + height: 48, + padding: EdgeInsets.only(right: 6), + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: ThemeColors.background, + foregroundColor: ThemeColors.primary, + ), + child: Text( + t.common.actions.cancel, + style: theme.textTheme.titleMedium?.apply( + color: ThemeColors.primary, + ), + ), + onPressed: () => Navigator.maybePop(context), + ), + ), + ), + Expanded( + child: Container( + height: 48, + padding: EdgeInsets.only(left: 6), + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: ThemeColors.primary, + foregroundColor: ThemeColors.background, + ), + child: Text( + t.common.actions.save, + style: theme.textTheme.titleMedium?.apply( + color: ThemeColors.background, + ), + ), + onPressed: () => onSavePressed(context), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + Widget getPhotoPreviewOrIcon() { + if (_currentPhoto != null) { + return Container( + width: 150, + height: 120, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + shape: BoxShape.circle, + ), + child: GestureDetector( + onTap: acquireNewPhoto, + child: Image.file( + _currentPhoto!, + fit: BoxFit.cover, + ), + ), + ); + } else { + return Center( + child: GestureDetector( + onTap: acquireNewPhoto, + child: Icon( + Icons.photo_camera, + color: Colors.white, + size: 30.0, + ), + ), + ); + } + } + + void acquireNewPhoto() async { + final photo = await MediaHelper.acquirePhoto(context); + // final photoBytes = await reduceAndResize(photo); + + if (photo != null) { + setState(() { + _currentPhoto = photo; + }); + } + } + + Future reduceAndResize(File? photo) async { + if (photo == null) return null; + final fileContent = await photo.readAsBytes(); + return await MediaHelper.resizeAndReduceImage(fileContent, ImageType.jpeg); + } + + void onSavePressed(BuildContext localContext) async { + final reducedImage = await reduceAndResize(_currentPhoto); + if (!localContext.mounted) return; + Navigator.maybePop( + localContext, + PosterCreateModel( + location: widget.location, + street: streetTextController.text, + houseNumber: houseNumberTextController.text, + zipCode: zipCodeTextController.text, + city: cityTextController.text, + photo: reducedImage, + ), + ); + } +} diff --git a/lib/features/campaigns/screens/posters_screen.dart b/lib/features/campaigns/screens/posters_screen.dart index 48fe1458..ea3628bf 100644 --- a/lib/features/campaigns/screens/posters_screen.dart +++ b/lib/features/campaigns/screens/posters_screen.dart @@ -1,8 +1,20 @@ import 'package:flutter/widgets.dart'; +import 'package:go_router/go_router.dart'; +import 'package:gruene_app/app/services/gruene_api_campaigns_service.dart'; +import 'package:gruene_app/app/services/nominatim_service.dart'; +import 'package:gruene_app/app/theme/theme.dart'; +import 'package:gruene_app/features/campaigns/helper/media_helper.dart'; +import 'package:gruene_app/features/campaigns/models/posters/poster_create_model.dart'; +import 'package:gruene_app/features/campaigns/screens/poster_add.dart'; +import 'package:gruene_app/features/campaigns/widgets/app_route.dart'; +import 'package:gruene_app/features/campaigns/widgets/content_page.dart'; import 'package:gruene_app/features/campaigns/widgets/filter_chip_widget.dart'; +import 'package:gruene_app/features/campaigns/widgets/map.dart'; +import 'package:gruene_app/features/campaigns/widgets/map_controller.dart'; import 'package:gruene_app/i18n/translations.g.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; -class PostersScreen extends StatelessWidget { +class PostersScreen extends StatefulWidget { PostersScreen({super.key}); final List postersFilter = [ @@ -10,13 +22,97 @@ class PostersScreen extends StatelessWidget { FilterChipModel(t.campaigns.filters.polling_stations, false), FilterChipModel(t.campaigns.filters.experience_areas, false), ]; + + @override + State createState() => _PostersScreenState(); +} + +class _PostersScreenState extends State { + late MapController _mapController; + final GrueneApiCampaignsService _grueneApiService = GrueneApiCampaignsService(poiType: PoiServiceType.poster); + final NominatimService _nominatimService = NominatimService(); + @override - Widget build(BuildContext context) { + Widget build(localContext) { + MapContainer mapContainer = MapContainer( + onMapCreated: onMapCreated, + addPOIClicked: addPOIClicked, + loadVisibleItems: loadVisibleItems, + getMarkerImages: getMarkerImages, + ); + return Column( children: [ - FilterChipCampaign(postersFilter, >{}), - Center(child: Text(t.campaigns.posters.label)), + FilterChipCampaign(widget.postersFilter, >{}), + Expanded( + child: mapContainer, + ), ], ); } + + void onMapCreated(MapController controller) { + _mapController = controller; + } + + void addPOIClicked(LatLng location) async { + final currentRoute = GoRouterState.of(context); + + var locationAddress = _nominatimService.getLocationAddress(location); + + final photo = await MediaHelper.acquirePhoto(context); + + var navState = getNavState(); + final result = await navState.push( + AppRoute( + builder: (context) { + return FutureBuilder( + future: locationAddress.timeout(const Duration(milliseconds: 800), onTimeout: () => AddressModel()), + builder: (context, AsyncSnapshot snapshot) { + if (!snapshot.hasData && !snapshot.hasError) { + return Container( + color: ThemeColors.secondary, + ); + } + + final address = snapshot.data; + return ContentPage( + title: currentRoute.name ?? '', + child: PosterAddScreen( + location: location, + address: address!, + photo: photo, + ), + ); + }, + ); + }, + ), + ); + + if (result != null) { + final newPoster = result; + + final markerItem = await _grueneApiService.createNewPoster(newPoster); + _mapController.addMarkerItem(markerItem); + } + } + + NavigatorState getNavState() => Navigator.of(context, rootNavigator: true); + + void loadVisibleItems(LatLng locationSW, LatLng locationNE) async { + // final resultHealth = await _grueneApiService.getHealth(); + // print(resultHealth.error); + + final markerItems = await _grueneApiService.loadPoisInRegion(locationSW, locationNE); + _mapController.setMarkerSource(markerItems); + } + + Map getMarkerImages() { + return { + 'poster': 'assets/symbols/posters/poster.png', + 'poster_damaged': 'assets/symbols/posters/poster_damaged.png', + 'poster_taken_down': 'assets/symbols/posters/poster_taken_down.png', + }; + } } diff --git a/lib/features/campaigns/widgets/app_route.dart b/lib/features/campaigns/widgets/app_route.dart new file mode 100644 index 00000000..652f26bf --- /dev/null +++ b/lib/features/campaigns/widgets/app_route.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; + +class AppRoute extends MaterialPageRoute { + AppRoute({required WidgetBuilder builder, super.settings}) + : super( + builder: (BuildContext context) { + // final theme = Theme.of(context); + return Material(child: builder(context)); + }, + ); +} diff --git a/lib/features/campaigns/widgets/content_page.dart b/lib/features/campaigns/widgets/content_page.dart new file mode 100644 index 00000000..fb518c41 --- /dev/null +++ b/lib/features/campaigns/widgets/content_page.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:gruene_app/features/campaigns/widgets/custom_app_bar.dart'; + +class ContentPage extends StatelessWidget { + final String title; + final Widget child; + + const ContentPage({super.key, required this.title, required this.child}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Scaffold( + backgroundColor: theme.colorScheme.secondary, + body: child, + appBar: CustomAppBar( + title: title, + ), + ); + } +} diff --git a/lib/features/campaigns/widgets/custom_app_bar.dart b/lib/features/campaigns/widgets/custom_app_bar.dart new file mode 100644 index 00000000..0414ba56 --- /dev/null +++ b/lib/features/campaigns/widgets/custom_app_bar.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:gruene_app/app/constants/routes.dart'; +import 'package:gruene_app/app/theme/theme.dart'; +import 'package:gruene_app/app/widgets/icon.dart'; + +class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { + final String title; + const CustomAppBar({super.key, required this.title}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return AppBar( + title: Text( + title, + style: theme.textTheme.displayMedium?.apply(color: theme.colorScheme.surface), + ), + leading: BackButton(), + foregroundColor: theme.colorScheme.surface, + backgroundColor: theme.primaryColor, + centerTitle: true, + actions: [ + IconButton( + icon: CustomIcon( + path: 'assets/icons/settings.svg', + color: ThemeColors.background, + ), + onPressed: () => context.push(Routes.settings), + ), + ], + ); + } + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} diff --git a/lib/features/campaigns/widgets/custom_sliver_app_bar.dart b/lib/features/campaigns/widgets/custom_sliver_app_bar.dart new file mode 100644 index 00000000..0b8fa680 --- /dev/null +++ b/lib/features/campaigns/widgets/custom_sliver_app_bar.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:gruene_app/app/constants/routes.dart'; +import 'package:gruene_app/app/theme/theme.dart'; +import 'package:gruene_app/app/widgets/icon.dart'; + +class CustomSliverAppBar extends StatelessWidget { + final String title; + + const CustomSliverAppBar({super.key, required this.title}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final foregroundColor = theme.primaryColor; + return SliverAppBar( + backgroundColor: foregroundColor, + leading: BackButton(color: foregroundColor), + iconTheme: IconThemeData(color: foregroundColor), + title: Text(title, style: theme.textTheme.titleMedium?.apply(color: theme.appBarTheme.foregroundColor)), + centerTitle: true, + actions: [ + IconButton( + icon: CustomIcon( + path: 'assets/icons/settings.svg', + color: ThemeColors.background, + ), + onPressed: () => context.push(Routes.settings), + ), + ], + pinned: true, + ); + } +} diff --git a/lib/features/campaigns/widgets/map.dart b/lib/features/campaigns/widgets/map.dart new file mode 100644 index 00000000..6a487c36 --- /dev/null +++ b/lib/features/campaigns/widgets/map.dart @@ -0,0 +1,155 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:gruene_app/app/constants/config.dart'; +import 'package:gruene_app/features/campaigns/helper/marker_item_helper.dart'; +import 'package:gruene_app/features/campaigns/helper/util.dart'; +import 'package:gruene_app/features/campaigns/models/marker_item_model.dart'; +import 'package:gruene_app/features/campaigns/widgets/map_controller.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; + +typedef OnMapCreatedCallback = void Function(MapController controller); +typedef AddPOIClickedCallback = void Function(LatLng location); +typedef LoadVisibleItemsCallBack = void Function(LatLng locationSW, LatLng locationNE); +typedef GetMarkerImagesCallback = Map Function(); + +class MapContainer extends StatefulWidget { + final OnMapCreatedCallback? onMapCreated; + final AddPOIClickedCallback? addPOIClicked; + final LoadVisibleItemsCallBack? loadVisibleItems; + final GetMarkerImagesCallback getMarkerImages; + + const MapContainer({ + super.key, + required this.onMapCreated, + required this.addPOIClicked, + required this.loadVisibleItems, + required this.getMarkerImages, + }); + + @override + State createState() => _MapContainerState(); +} + +class _MapContainerState extends State implements MapController { + MapLibreMapController? _controller; + final MarkerItemManager _markerItemManager = MarkerItemManager(); + bool _isMapInitialized = false; + + final LatLngBounds _cameraTargetBounds = LatLngBounds( + southwest: LatLng(46.8, 5.6), + northeast: LatLng(55.1, 15.5), + ); //typically Germany + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Stack( + children: [ + MapLibreMap( + // minMaxZoomPreference: MinMaxZoomPreference(14, 18), + styleString: Config.maplibreUrl, + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition(target: LatLng(52.528810, 13.379300), zoom: 16), + onStyleLoadedCallback: _onStyleLoadedCallback, + cameraTargetBounds: CameraTargetBounds(_cameraTargetBounds), + trackCameraPosition: true, + onCameraIdle: _onCameraIdle, + onMapClick: _onMapClick, + + // rotateGesturesEnabled: false, + ), + Center( + child: Container( + padding: + EdgeInsets.only(bottom: 65 /* height of the add_marker icon to position it exactly on the middle */), + child: GestureDetector( + onTap: _onIconTap, + child: SvgPicture.asset('assets/symbols/add_marker.svg'), + ), + ), + ), + ], + ), + ); + } + + void _onMapCreated(MapLibreMapController controller) async { + if (!mounted) return; + + setState(() { + _controller = controller; + _isMapInitialized = true; + }); + + final onMapCreated = widget.onMapCreated; + if (onMapCreated != null) { + onMapCreated(this); + } + } + + void _onIconTap() { + final addPOIClicked = widget.addPOIClicked; + + if (addPOIClicked != null) { + addPOIClicked(_controller!.cameraPosition!.target); + } + } + + void _onMapClick(Point point, LatLng coordinates) {} + + void _onCameraIdle() async { + if (!_isMapInitialized) return; + final visRegion = await _controller?.getVisibleRegion(); + + widget.loadVisibleItems!(visRegion!.southwest, visRegion.northeast); + } + + void _onStyleLoadedCallback() async { + widget.getMarkerImages().forEach((x, y) async { + await addImageFromAsset(_controller!, x, y); + }); + + _controller!.addGeoJsonSource('markers', MarkerItemHelper.transformListToGeoJson([]).toJson()); + + await _controller!.addSymbolLayer( + 'markers', + 'symbols', + const SymbolLayerProperties( + iconImage: ['get', 'type'], + iconSize: 2, + iconAllowOverlap: true, + ), + filter: [ + '!', + ['has', 'point_count'], + ], + ); + } + + @override + void setMarkerSource(List poiList) { + _markerItemManager.addMarkers(poiList); + _controller! + .setGeoJsonSource('markers', MarkerItemHelper.transformListToGeoJson(_markerItemManager.getMarkers()).toJson()); + } + + @override + void addMarkerItem(MarkerItemModel markerItem) { + setMarkerSource([markerItem]); + } +} + +class MarkerItemManager { + final List loadedMarkers = []; + + void addMarkers(List poiList) { + loadedMarkers.retainWhere((oldMarker) => poiList.any((newMarker) => newMarker.id != oldMarker.id)); + loadedMarkers.addAll(poiList); + } + + List getMarkers() { + return loadedMarkers; + } +} diff --git a/lib/features/campaigns/widgets/map_controller.dart b/lib/features/campaigns/widgets/map_controller.dart new file mode 100644 index 00000000..3ec4c669 --- /dev/null +++ b/lib/features/campaigns/widgets/map_controller.dart @@ -0,0 +1,7 @@ +import 'package:gruene_app/features/campaigns/models/marker_item_model.dart'; + +abstract class MapController { + void setMarkerSource(List poiList) {} + + void addMarkerItem(MarkerItemModel markerItem) {} +} diff --git a/lib/features/campaigns/widgets/sliver_content_page.dart b/lib/features/campaigns/widgets/sliver_content_page.dart new file mode 100644 index 00000000..aca184f5 --- /dev/null +++ b/lib/features/campaigns/widgets/sliver_content_page.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:gruene_app/features/campaigns/widgets/custom_sliver_app_bar.dart'; + +class SliverContentPage extends StatelessWidget { + final String title; + final List children; + + const SliverContentPage({super.key, required this.title, required this.children}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return DecoratedBox( + decoration: BoxDecoration(color: theme.colorScheme.primary), + child: CustomScrollView( + slivers: [ + CustomSliverAppBar(title: title), + SliverPadding( + padding: const EdgeInsets.all(10), + sliver: SliverList( + delegate: SliverChildListDelegate(children), + ), + ), + ], + ), + ); + } +} diff --git a/lib/features/campaigns/widgets/textinputfield.dart b/lib/features/campaigns/widgets/textinputfield.dart new file mode 100644 index 00000000..5272ecd3 --- /dev/null +++ b/lib/features/campaigns/widgets/textinputfield.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:gruene_app/app/theme/theme.dart'; + +class TextInputField extends StatefulWidget { + final String labelText; + + final double? width; + + final TextEditingController? textController; + + const TextInputField({required this.labelText, this.width, this.textController, super.key}); + + @override + State createState() => _TextInputFieldState(); +} + +class _TextInputFieldState extends State { + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Container( + width: widget.width, + padding: EdgeInsets.symmetric(vertical: 6, horizontal: 9), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: TextFormField( + controller: widget.textController, + style: theme.textTheme.bodyMedium?.apply(color: ThemeColors.text), + decoration: InputDecoration( + labelText: widget.labelText, + border: InputBorder.none, + labelStyle: theme.textTheme.labelMedium?.apply(color: ThemeColors.textDisabled), + floatingLabelStyle: theme.textTheme.labelSmall?.apply(color: ThemeColors.textDisabled), + ), + ), + ); + } +} diff --git a/lib/i18n/app_de.json b/lib/i18n/app_de.json index 2cc6304f..b503dd7e 100644 --- a/lib/i18n/app_de.json +++ b/lib/i18n/app_de.json @@ -1,6 +1,10 @@ { "common": { - "appName": "Grüne App" + "appName": "Grüne App", + "actions": { + "save": "Speichern", + "cancel": "Abbrechen" + } }, "news": { "news": "Artikel", @@ -17,7 +21,8 @@ "experience_areas": "Erfahrungsgebiete" }, "posters": { - "label": "Plakate" + "label": "Plakate", + "addPoster": "Plakat eintragen" }, "door": { "label": "Haustür" @@ -30,6 +35,12 @@ }, "statistic": { "label": "Statistik" + }, + "address": { + "street": "Straße", + "housenumber": "Hausnr.", + "zipcode": "PLZ", + "city_or_place": "Stadt / Ort" } }, "profiles": { @@ -72,4 +83,4 @@ "discover": "App erkunden", "discoverDescription": "Erfahre hier, was Dich erwartet." } -} +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 17af80d3..9cb44803 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,714 +1,1255 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - ansicolor: - dependency: transitive - description: - name: ansicolor - sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" - url: "https://pub.dev" - source: hosted - version: "2.0.3" - archive: - dependency: transitive - description: - name: archive - sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d - url: "https://pub.dev" - source: hosted - version: "3.6.1" - args: - dependency: transitive - description: - name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 - url: "https://pub.dev" - source: hosted - version: "2.6.0" - async: - dependency: transitive - description: - name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 - url: "https://pub.dev" - source: hosted - version: "2.12.0" - bloc: - dependency: transitive - description: - name: bloc - sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" - url: "https://pub.dev" - source: hosted - version: "8.1.4" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - collection: - dependency: transitive - description: - name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a - url: "https://pub.dev" - source: hosted - version: "1.18.0" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - csslib: - dependency: transitive - description: - name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - csv: - dependency: transitive - description: - name: csv - sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c - url: "https://pub.dev" - source: hosted - version: "6.0.0" - dio: - dependency: "direct main" - description: - name: dio - sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" - url: "https://pub.dev" - source: hosted - version: "5.7.0" - dio_web_adapter: - dependency: transitive - description: - name: dio_web_adapter - sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - equatable: - dependency: "direct main" - description: - name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 - url: "https://pub.dev" - source: hosted - version: "2.0.5" - ffi: - dependency: transitive - description: - name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_appauth: - dependency: "direct main" - description: - name: flutter_appauth - sha256: "6ab0e7fb2cb66db472a71c00e0f0d0888f186d308beaef4bba1a6113fa861096" - url: "https://pub.dev" - source: hosted - version: "8.0.0+1" - flutter_appauth_platform_interface: - dependency: transitive - description: - name: flutter_appauth_platform_interface - sha256: ccf5e1d8c40dd35b297290b33cc1896648b4b92a2ec3f62a436c62a8eef9a9db - url: "https://pub.dev" - source: hosted - version: "8.0.0" - flutter_bloc: - dependency: "direct main" - description: - name: flutter_bloc - sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a - url: "https://pub.dev" - source: hosted - version: "8.1.6" - flutter_dotenv: - dependency: "direct main" - description: - name: flutter_dotenv - sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b - url: "https://pub.dev" - source: hosted - version: "5.2.1" - flutter_inappwebview: - dependency: "direct main" - description: - name: flutter_inappwebview - sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.dev" - source: hosted - version: "6.1.5" - flutter_inappwebview_android: - dependency: transitive - description: - name: flutter_inappwebview_android - sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.dev" - source: hosted - version: "1.1.3" - flutter_inappwebview_internal_annotations: - dependency: transitive - description: - name: flutter_inappwebview_internal_annotations - sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter_inappwebview_ios: - dependency: transitive - description: - name: flutter_inappwebview_ios - sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_macos: - dependency: transitive - description: - name: flutter_inappwebview_macos - sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_platform_interface: - dependency: transitive - description: - name: flutter_inappwebview_platform_interface - sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.dev" - source: hosted - version: "1.3.0+1" - flutter_inappwebview_web: - dependency: transitive - description: - name: flutter_inappwebview_web - sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_inappwebview_windows: - dependency: transitive - description: - name: flutter_inappwebview_windows - sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" - url: "https://pub.dev" - source: hosted - version: "5.0.0" - flutter_localizations: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_native_splash: - dependency: "direct main" - description: - name: flutter_native_splash - sha256: ee5c9bd2b74ea8676442fd4ab876b5d41681df49276488854d6c81a5377c0ef1 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - flutter_secure_storage: - dependency: "direct main" - description: - name: flutter_secure_storage - sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0" - url: "https://pub.dev" - source: hosted - version: "9.2.2" - flutter_secure_storage_linux: - dependency: transitive - description: - name: flutter_secure_storage_linux - sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - flutter_secure_storage_macos: - dependency: transitive - description: - name: flutter_secure_storage_macos - sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81" - url: "https://pub.dev" - source: hosted - version: "3.1.2" - flutter_secure_storage_platform_interface: - dependency: transitive - description: - name: flutter_secure_storage_platform_interface - sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_secure_storage_web: - dependency: transitive - description: - name: flutter_secure_storage_web - sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - flutter_secure_storage_windows: - dependency: transitive - description: - name: flutter_secure_storage_windows - sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" - url: "https://pub.dev" - source: hosted - version: "2.0.10+1" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - get_it: - dependency: "direct main" - description: - name: get_it - sha256: ff97e5e7b2e82e63c82f5658c6ba2605ea831f0f7489b0d2fb255d817ec4eb5e - url: "https://pub.dev" - source: hosted - version: "8.0.0" - go_router: - dependency: "direct main" - description: - name: go_router - sha256: "6f1b756f6e863259a99135ff3c95026c3cdca17d10ebef2bba2261a25ddc8bbc" - url: "https://pub.dev" - source: hosted - version: "14.3.0" - google_fonts: - dependency: "direct main" - description: - name: google_fonts - sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 - url: "https://pub.dev" - source: hosted - version: "6.2.1" - html: - dependency: transitive - description: - name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" - url: "https://pub.dev" - source: hosted - version: "0.15.5" - http: - dependency: transitive - description: - name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 - url: "https://pub.dev" - source: hosted - version: "1.2.2" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - image: - dependency: transitive - description: - name: image - sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d - url: "https://pub.dev" - source: hosted - version: "4.3.0" - intl: - dependency: transitive - description: - name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf - url: "https://pub.dev" - source: hosted - version: "0.19.0" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - json2yaml: - dependency: transitive - description: - name: json2yaml - sha256: da94630fbc56079426fdd167ae58373286f603371075b69bf46d848d63ba3e51 - url: "https://pub.dev" - source: hosted - version: "3.0.1" - jwt_decoder: - dependency: "direct main" - description: - name: jwt_decoder - sha256: "54774aebf83f2923b99e6416b4ea915d47af3bde56884eb622de85feabbc559f" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - lints: - dependency: transitive - description: - name: lints - sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" - url: "https://pub.dev" - source: hosted - version: "5.0.0" - logger: - dependency: "direct main" - description: - name: logger - sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 - url: "https://pub.dev" - source: hosted - version: "1.15.0" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - path: - dependency: transitive - description: - name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" - url: "https://pub.dev" - source: hosted - version: "1.9.0" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "45f7d6bba1128761de5540f39d5ca000ea8a1f22f06b76b61094a60a2997bd0e" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 - url: "https://pub.dev" - source: hosted - version: "2.1.4" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a - url: "https://pub.dev" - source: hosted - version: "2.2.12" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 - url: "https://pub.dev" - source: hosted - version: "2.4.0" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 - url: "https://pub.dev" - source: hosted - version: "6.0.2" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - provider: - dependency: transitive - description: - name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c - url: "https://pub.dev" - source: hosted - version: "6.1.2" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - slang: - dependency: "direct main" - description: - name: slang - sha256: b04db2dbaf927b28600a2f8a272a3bf2ae309556dcc5d6beb02d66af0be39e4c - url: "https://pub.dev" - source: hosted - version: "4.1.0" - slang_flutter: - dependency: "direct main" - description: - name: slang_flutter - sha256: "59988f37bb8b50d96ee46832a8a389036c0da26c04b1b1d4aa6690c00f70eccf" - url: "https://pub.dev" - source: hosted - version: "4.1.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - universal_io: - dependency: transitive - description: - name: universal_io - sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" - url: "https://pub.dev" - source: hosted - version: "2.2.2" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" - url: "https://pub.dev" - source: hosted - version: "1.1.11+1" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da - url: "https://pub.dev" - source: hosted - version: "1.1.11+1" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" - url: "https://pub.dev" - source: hosted - version: "1.1.11+1" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb - url: "https://pub.dev" - source: hosted - version: "1.1.0" - webview_flutter: - dependency: "direct main" - description: - name: webview_flutter - sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" - url: "https://pub.dev" - source: hosted - version: "4.10.0" - webview_flutter_android: - dependency: transitive - description: - name: webview_flutter_android - sha256: "86c2d01c37c4578ee46560109cf2e18fb271f0d080a796f09188d0952352e057" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - webview_flutter_platform_interface: - dependency: transitive - description: - name: webview_flutter_platform_interface - sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d - url: "https://pub.dev" - source: hosted - version: "2.10.0" - webview_flutter_wkwebview: - dependency: transitive - description: - name: webview_flutter_wkwebview - sha256: "3be297aa4ca78205abdd284cf55f168c35246c75b3079990ad8ba9d257681a30" - url: "https://pub.dev" - source: hosted - version: "3.16.2" - win32: - dependency: transitive - description: - name: win32 - sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2" - url: "https://pub.dev" - source: hosted - version: "5.8.0" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 - url: "https://pub.dev" - source: hosted - version: "6.5.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" - source: hosted - version: "3.1.2" -sdks: - dart: ">=3.5.3 <4.0.0" - flutter: ">=3.24.0" +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + url: "https://pub.dev" + source: hosted + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + url: "https://pub.dev" + source: hosted + version: "6.7.0" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" + url: "https://pub.dev" + source: hosted + version: "2.0.3" + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" + args: + dependency: transitive + description: + name: args + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + url: "https://pub.dev" + source: hosted + version: "2.6.0" + async: + dependency: transitive + description: + name: async + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + url: "https://pub.dev" + source: hosted + version: "2.12.0" + benchmark: + dependency: transitive + description: + name: benchmark + sha256: cb3eeea01e3f054df76ee9775ca680f3afa5f19f39b2bb426ba78ba27654493b + url: "https://pub.dev" + source: hosted + version: "0.3.0" + bloc: + dependency: transitive + description: + name: bloc + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" + url: "https://pub.dev" + source: hosted + version: "8.1.4" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" + url: "https://pub.dev" + source: hosted + version: "2.4.13" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 + url: "https://pub.dev" + source: hosted + version: "7.3.2" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" + camerawesome: + dependency: "direct main" + description: + name: camerawesome + sha256: "3619d5605fb14ab72c815532c1d9f635512c75df07b5a742b60a9a4b03b6081e" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + carousel_slider: + dependency: transitive + description: + name: carousel_slider + sha256: "7b006ec356205054af5beaef62e2221160ea36b90fb70a35e4deacd49d0349ae" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + chopper: + dependency: "direct main" + description: + name: chopper + sha256: "40899b729fb6d8969d967264b189efaf2452bc3ccf6ed0782d00f1d8a6161c31" + url: "https://pub.dev" + source: hosted + version: "8.0.3" + chopper_generator: + dependency: "direct dev" + description: + name: chopper_generator + sha256: de438569cba1e2a2888e8d91e3c2ac60106574eea7f36823ed0334e96146328a + url: "https://pub.dev" + source: hosted + version: "8.0.3" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" + source: hosted + version: "4.10.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + colorfilter_generator: + dependency: transitive + description: + name: colorfilter_generator + sha256: ccc2995e440b1d828d55d99150e7cad64624f3cb4a1e235000de3f93cf10d35c + url: "https://pub.dev" + source: hosted + version: "0.0.8" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + csv: + dependency: transitive + description: + name: csv + sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c + url: "https://pub.dev" + source: hosted + version: "6.0.0" + dart_sort_queue: + dependency: transitive + description: + name: dart_sort_queue + sha256: f3353ba8b4850e072d3368757f62edb79af34a9703c3e3df9c59342721f5f5b1 + url: "https://pub.dev" + source: hosted + version: "0.0.2+3" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" + url: "https://pub.dev" + source: hosted + version: "2.3.7" + dio: + dependency: "direct main" + description: + name: dio + sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" + url: "https://pub.dev" + source: hosted + version: "5.7.0" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + equatable: + dependency: "direct main" + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_appauth: + dependency: "direct main" + description: + name: flutter_appauth + sha256: "6ab0e7fb2cb66db472a71c00e0f0d0888f186d308beaef4bba1a6113fa861096" + url: "https://pub.dev" + source: hosted + version: "8.0.0+1" + flutter_appauth_platform_interface: + dependency: transitive + description: + name: flutter_appauth_platform_interface + sha256: ccf5e1d8c40dd35b297290b33cc1896648b4b92a2ec3f62a436c62a8eef9a9db + url: "https://pub.dev" + source: hosted + version: "8.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a + url: "https://pub.dev" + source: hosted + version: "8.1.6" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b + url: "https://pub.dev" + source: hosted + version: "5.2.1" + flutter_inappwebview: + dependency: "direct main" + description: + name: flutter_inappwebview + sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + flutter_inappwebview_android: + dependency: transitive + description: + name: flutter_inappwebview_android + sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_inappwebview_ios: + dependency: transitive + description: + name: flutter_inappwebview_ios + sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_macos: + dependency: transitive + description: + name: flutter_inappwebview_macos + sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 + url: "https://pub.dev" + source: hosted + version: "1.3.0+1" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_windows: + dependency: transitive + description: + name: flutter_inappwebview_windows + sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_native_splash: + dependency: "direct main" + description: + name: flutter_native_splash + sha256: ee5c9bd2b74ea8676442fd4ab876b5d41681df49276488854d6c81a5377c0ef1 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0" + url: "https://pub.dev" + source: hosted + version: "9.2.2" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + geotypes: + dependency: transitive + description: + name: geotypes + sha256: "5bedf57de92283133dd221e363812ef50eaaba414f0823b1974ef7d84b86991f" + url: "https://pub.dev" + source: hosted + version: "0.0.2" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: ff97e5e7b2e82e63c82f5658c6ba2605ea831f0f7489b0d2fb255d817ec4eb5e + url: "https://pub.dev" + source: hosted + version: "8.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: "6f1b756f6e863259a99135ff3c95026c3cdca17d10ebef2bba2261a25ddc8bbc" + url: "https://pub.dev" + source: hosted + version: "14.3.0" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + html: + dependency: transitive + description: + name: html + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" + url: "https://pub.dev" + source: hosted + version: "0.15.5" + http: + dependency: "direct main" + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: "direct main" + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: "direct main" + description: + name: image + sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d + url: "https://pub.dev" + source: hosted + version: "4.3.0" + intl: + dependency: "direct main" + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json2yaml: + dependency: transitive + description: + name: json2yaml + sha256: da94630fbc56079426fdd167ae58373286f603371075b69bf46d848d63ba3e51 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b + url: "https://pub.dev" + source: hosted + version: "6.8.0" + jwt_decoder: + dependency: "direct main" + description: + name: jwt_decoder + sha256: "54774aebf83f2923b99e6416b4ea915d47af3bde56884eb622de85feabbc559f" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + logger: + dependency: "direct main" + description: + name: logger + sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" + maplibre_gl: + dependency: "direct main" + description: + name: maplibre_gl + sha256: ea2fa443e7d5dc18db7f37a0f6f5af40642888c56b81a14441aeddea077adaea + url: "https://pub.dev" + source: hosted + version: "0.20.0" + maplibre_gl_platform_interface: + dependency: "direct main" + description: + name: maplibre_gl_platform_interface + sha256: "718c3503f36936fbf35c34d6ddf8bf770474c5ba1e6cb1d8caece44efae424af" + url: "https://pub.dev" + source: hosted + version: "0.20.0" + maplibre_gl_web: + dependency: transitive + description: + name: maplibre_gl_web + sha256: e7d71b08f24dca70e9c9cf841b096704a677e6239447d87220ec071355768149 + url: "https://pub.dev" + source: hosted + version: "0.20.0" + markdown: + dependency: transitive + description: + name: markdown + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + url: "https://pub.dev" + source: hosted + version: "7.2.2" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + matrix2d: + dependency: transitive + description: + name: matrix2d + sha256: "188718dd3bc2a31e372cfd0791b0f77f4f13ea76164147342cc378d9132949e7" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "45f7d6bba1128761de5540f39d5ca000ea8a1f22f06b76b61094a60a2997bd0e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + url: "https://pub.dev" + source: hosted + version: "2.1.4" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a + url: "https://pub.dev" + source: hosted + version: "2.2.12" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + url: "https://pub.dev" + source: hosted + version: "2.4.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + provider: + dependency: transitive + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + qs_dart: + dependency: transitive + description: + name: qs_dart + sha256: be73d060d29c0716ded88380ba32e87ce8105f0ba234edb3edefa0d74d47d64b + url: "https://pub.dev" + source: hosted + version: "1.2.4" + rbush: + dependency: transitive + description: + name: rbush + sha256: "48b683421b4afb43a642f82c6aa31911e54f3069143d31c7d33cbe329df13403" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + recursive_regex: + dependency: transitive + description: + name: recursive_regex + sha256: f7252e3d3dfd1665e594d9fe035eca6bc54139b1f2fee38256fa427ea41adc60 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + slang: + dependency: "direct main" + description: + name: slang + sha256: b04db2dbaf927b28600a2f8a272a3bf2ae309556dcc5d6beb02d66af0be39e4c + url: "https://pub.dev" + source: hosted + version: "4.1.0" + slang_flutter: + dependency: "direct main" + description: + name: slang_flutter + sha256: "59988f37bb8b50d96ee46832a8a389036c0da26c04b1b1d4aa6690c00f70eccf" + url: "https://pub.dev" + source: hosted + version: "4.1.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + swagger_dart_code_generator: + dependency: "direct dev" + description: + name: swagger_dart_code_generator + sha256: e6fab279c2adb3f91aa170c9126601d22e1485217dddc1443cf3c05eb6480d45 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + sweepline_intersections: + dependency: transitive + description: + name: sweepline_intersections + sha256: a665c707200a4f07140a4029b41a7c4883beb3f04322cd8e08ebf650f69e1176 + url: "https://pub.dev" + source: hosted + version: "0.0.4" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + url: "https://pub.dev" + source: hosted + version: "0.7.3" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + turf: + dependency: "direct main" + description: + name: turf + sha256: "75347c45a5c1de805db7cb182286f05a3770e01546626c4dc292709d15cbe436" + url: "https://pub.dev" + source: hosted + version: "0.0.10" + turf_equality: + dependency: transitive + description: + name: turf_equality + sha256: f0f44ffe389547941358e0d3d4a747db2bd56115b32ff1cede5e5bdf3126a3e2 + url: "https://pub.dev" + source: hosted + version: "0.1.0" + turf_pip: + dependency: transitive + description: + name: turf_pip + sha256: ba4fd414baffd5d7b30880658ad6db82461c49ec023f8ffd0c23d398ad8b14be + url: "https://pub.dev" + source: hosted + version: "0.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + weak_map: + dependency: transitive + description: + name: weak_map + sha256: "95ca338f0cdf5f0022cc283dfa4d97f6f6b03752f67eca85ebe6d7a679ffe3ed" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" + url: "https://pub.dev" + source: hosted + version: "4.10.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: "86c2d01c37c4578ee46560109cf2e18fb271f0d080a796f09188d0952352e057" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: "3be297aa4ca78205abdd284cf55f168c35246c75b3079990ad8ba9d257681a30" + url: "https://pub.dev" + source: hosted + version: "3.16.2" + win32: + dependency: transitive + description: + name: win32 + sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2" + url: "https://pub.dev" + source: hosted + version: "5.8.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.5.3 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 677a6c98..b35b8ec9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,100 +1,121 @@ -name: gruene_app -description: "App for the German party BÜNDNIS 90/DIE GRÜNEN" -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -environment: - sdk: ^3.5.3 - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - flutter_localizations: - sdk: flutter - flutter_bloc: ^8.1.6 - get_it: ^8.0.0 - dio: ^5.7.0 - slang: ^4.1.0 - slang_flutter: ^4.1.0 - go_router: ^14.3.0 - google_fonts: ^6.2.1 - flutter_svg: ^2.0.10+1 - flutter_appauth: ^8.0.0+1 - flutter_secure_storage: ^9.2.2 - flutter_dotenv: ^5.2.1 - flutter_inappwebview: ^6.1.5 - equatable: ^2.0.5 - logger: ^2.4.0 - jwt_decoder: ^2.0.1 - flutter_native_splash: ^2.4.2 - webview_flutter: ^4.10.0 - -dev_dependencies: - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^5.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - assets: - - assets/bottom_navigation/ - - assets/icons/ - - assets/splash/ - - assets/graphics/ - - .env - - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package - -flutter_native_splash: - color: "#ffffff" - image: assets/splash/logo.png - android_12: - color: "#ffffff" - image: assets/splash/logo_android12.png - web: false - android_gravity: center +name: gruene_app +description: "App for the German party BÜNDNIS 90/DIE GRÜNEN" +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +environment: + sdk: ^3.5.3 + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + flutter_localizations: + sdk: flutter + flutter_bloc: ^8.1.6 + get_it: ^8.0.0 + dio: ^5.7.0 + slang: ^4.1.0 + slang_flutter: ^4.1.0 + go_router: ^14.3.0 + google_fonts: ^6.2.1 + flutter_svg: ^2.0.10+1 + flutter_appauth: ^8.0.0+1 + flutter_secure_storage: ^9.2.2 + flutter_dotenv: ^5.2.1 + flutter_inappwebview: ^6.1.5 + equatable: ^2.0.5 + logger: ^2.4.0 + jwt_decoder: ^2.0.1 + flutter_native_splash: ^2.4.2 + webview_flutter: ^4.10.0 + maplibre_gl: ^0.20.0 + maplibre_gl_platform_interface: ^0.20.0 +#--------- swagger_dart_code_generator -------------- + chopper: ^8.0.0 + json_annotation: ^4.8.0 +#---------------------------------------------------- + http: ^1.2.2 + turf: ^0.0.10 + camerawesome: ^2.1.0 + intl: ^0.19.0 + image: ^4.3.0 + http_parser: ^4.0.2 + +dev_dependencies: + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^5.0.0 +#--------- swagger_dart_code_generator -------------- + build_runner: ^2.3.3 + chopper_generator: ^8.0.0 + json_serializable: ^6.6.1 + swagger_dart_code_generator: ^3.0.1 +#---------------------------------------------------- + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + uses-material-design: true + assets: + - assets/bottom_navigation/ + - assets/icons/ + - assets/splash/ + - assets/graphics/ + - assets/symbols/ + - assets/symbols/posters/ + - .env + + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package + +flutter_native_splash: + color: "#ffffff" + image: assets/splash/logo.png + android_12: + color: "#ffffff" + image: assets/splash/logo_android12.png + web: false + android_gravity: center ios_content_mode: scaleAspectFit \ No newline at end of file diff --git a/swaggers/gruene-api.yaml b/swaggers/gruene-api.yaml new file mode 100644 index 00000000..69865efc --- /dev/null +++ b/swaggers/gruene-api.yaml @@ -0,0 +1,2659 @@ +openapi: 3.0.0 +paths: + /v1/users: + get: + operationId: findUsers + summary: Find users + parameters: + - name: search + required: false + in: query + description: Search term to look for in firstname, lastname, email, username. + schema: + type: string + - name: userIds + required: false + in: query + description: Only return users with matching user id. + schema: + type: array + items: + type: string + - name: limit + required: false + in: query + schema: + minimum: 1 + maximum: 200 + type: number + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindUsersResponse' + '401': + description: '' + tags: + - users + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/users/self: + get: + operationId: getSelf + summary: Get the authenticated user + parameters: [] + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: No user provided by used authentication method + '401': + description: '' + tags: + - users + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/users/{userId}: + get: + operationId: getUser + summary: Get user by id + parameters: + - name: userId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/User ' + '401': + description: '' + '404': + description: '' + tags: + - users + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/users/{userId}/rbac-structure: + get: + operationId: getUserRbacStructure + summary: Get user RBAC structure + parameters: + - name: userId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/UserRbacStructure' + '401': + description: '' + '404': + description: '' + tags: + - users + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/party/organizations: + get: + operationId: findOrganizations + summary: Find all organizations + parameters: [] + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindNbOrganizationsResponse' + '401': + description: '' + tags: + - nb-api + security: + - basic: [] + - api_key: [] + /v1/party/groups: + get: + operationId: findGroups + summary: Find all groups + parameters: + - required: false + description: Filter by external reference type + name: filter[external_refs.type] + in: query + schema: + example: SHERPA + enum: + - SHERPA + type: string + - required: false + description: Filter by external reference ID (sherpa role id) + name: filter[external_refs.key] + in: query + schema: + example: '12345678' + type: string + - required: false + description: Filter by role level + name: filter[level] + in: query + schema: + enum: + - DE:BUNDESVERBAND + - DE:LANDESVERBAND + - DE:KREISVERBAND + - DE:ORTSVERBAND + type: string + - required: false + description: Filter by role type + name: filter[type] + in: query + schema: + example: EXECUTIVE_BOARD + type: string + - required: false + description: Filter by role slug + name: filter[slug] + in: query + schema: + example: KV_EXECUTIVE_BOARD + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindNbGroupsResponse' + '401': + description: '' + tags: + - nb-api + security: + - basic: [] + - api_key: [] + /v1/party/regionalchapters: + get: + operationId: findRegionalChapters + summary: Find all regional chapters + parameters: + - name: limit + required: false + in: query + description: Page limit + schema: + minimum: 1 + type: number + - name: offset + required: false + in: query + description: Page offset + schema: + minimum: 0 + type: number + - required: false + description: Filter by query + name: filter[query] + in: query + schema: + type: string + - required: false + description: Filter by ID prefix + name: filter[id_prefix] + in: query + schema: + maxLength: 8 + type: string + - required: false + description: Filter by type + name: filter[type] + in: query + schema: + enum: + - BV + - LV + - KV + - OV + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindNbRegionalChaptersResponse' + '401': + description: '' + tags: + - nb-api + security: + - basic: [] + - api_key: [] + /v1/party/regionalchapters/{divisionKey}: + get: + operationId: getRegionalChapter + summary: Get regional chapter by division key + parameters: + - name: divisionKey + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/NbRegionalChapter' + '401': + description: '' + tags: + - nb-api + security: + - basic: [] + - api_key: [] + /v1/profiles: + get: + operationId: findProfiles + summary: Find user profiles + parameters: + - name: limit + required: false + in: query + schema: + minimum: 1 + default: 20 + type: number + - name: tags + required: false + in: query + description: Filter by profile tag ids + schema: + type: array + items: + type: string + - name: offset + required: false + in: query + schema: + minimum: 0 + type: number + - name: search + required: false + in: query + description: Search term to look for in firstName, lastName and username + schema: + type: string + - name: division + required: false + in: query + description: |- + Division key to filter profiles. + Only include profiles that are member of given division. + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindProfilesResponse' + '401': + description: '' + tags: + - profiles + security: + - api_key: [] + - bearer: [] + - oauth2: [] + post: + operationId: createProfile + summary: Create user profile + parameters: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateProfile' + responses: + '201': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Profile' + '401': + description: '' + tags: + - profiles + security: + - api_key: [] + - bearer: [] + - oauth2: [] + /v1/profiles/self: + get: + operationId: getOwnProfile + summary: Get the authenticated user's profile + parameters: [] + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Profile' + '400': + description: No user provided by used authentication method + '401': + description: '' + tags: + - profiles + security: + - api_key: [] + - bearer: [] + - oauth2: [] + /v1/profiles/{profileId}: + get: + operationId: getProfile + summary: Get a user profile + parameters: + - name: profileId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/PublicProfile' + '401': + description: '' + '404': + description: '' + tags: + - profiles + security: + - api_key: [] + - bearer: [] + - oauth2: [] + put: + operationId: updateProfile + summary: Update user profile + description: >- + When updating the collection attributes like `messengers` all items must + be included. Omitting an item means it will be deleted. If an `id` + attribute is present it means update the give item. Omitting the `id` + attribute will add a new item to the collection. + parameters: + - name: profileId + required: true + in: path + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateProfile' + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Profile' + '400': + description: No user provided by used authentication method + '401': + description: '' + tags: + - profiles + security: + - api_key: [] + - bearer: [] + - oauth2: [] + delete: + operationId: deleteProfile + summary: Delete user profile + parameters: + - name: profileId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Profile' + '401': + description: '' + '404': + description: '' + tags: + - profiles + security: + - api_key: [] + - bearer: [] + - oauth2: [] + /v1/profiles/{profileId}/image: + put: + operationId: updateProfileImage + summary: Update profile image + requestBody: + content: + multipart/form-data: + schema: + type: object + required: + - profileImage + properties: + profileImage: + type: file + parameters: + - name: profileId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Profile' + '400': + description: No user provided by used authentication method + '401': + description: '' + tags: + - profiles + security: + - api_key: [] + - bearer: [] + - oauth2: [] + delete: + operationId: deleteProfileImage + summary: Delete user profile image + parameters: + - name: profileId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Profile' + '400': + description: No user provided by used authentication method + '401': + description: '' + tags: + - profiles + security: + - api_key: [] + - bearer: [] + - oauth2: [] + /v1/profile-tags: + get: + operationId: findProfileTags + summary: List profile tags + parameters: + - name: limit + required: false + in: query + schema: + minimum: 1 + default: 20 + type: number + - name: offset + required: false + in: query + schema: + minimum: 0 + type: number + - name: search + required: false + in: query + description: Search label attributes for substring + schema: + type: string + - name: type + required: false + in: query + description: Filter by type + schema: + example: interest + enum: + - skill + - interest + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindProfileTagsResponse' + '401': + description: '' + tags: + - profiles + security: + - bearer: [] + - api_key: [] + /v1/offboarding/users/self: + get: + operationId: findUsersToOffboard + summary: >- + Find users to offboard for the service associated with the used + credentials + parameters: + - name: limit + required: false + in: query + description: >- + Amount of items to retrieve. This value is ignored when a cursor is + set. + schema: + minimum: 1 + maximum: 1000 + default: 200 + type: number + - name: after + required: false + in: query + description: Cursor for the next result set. + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindOffboardingUsersResponse' + '401': + description: '' + tags: + - offboarding + security: + - basic: [] + /v1/offboarding/users/self/batch: + post: + operationId: batchUpdateOffboardingServiceUsers + summary: Batch update offboarding users for the authenticated service. + parameters: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BatchUpdateOffboardingServiceUsers' + responses: + '201': + description: '' + '401': + description: '' + tags: + - offboarding + security: + - basic: [] + /v1/divisions: + get: + operationId: findDivisions + summary: Find divisions + parameters: + - name: limit + required: false + in: query + schema: + minimum: 1 + default: 20 + type: number + - name: offset + required: false + in: query + schema: + minimum: 0 + type: number + - name: hierarchy + required: false + in: query + description: Filter by hierarchy + schema: + example: GR + enum: + - GR + - GJ + - KPV + type: string + - name: level + required: false + in: query + description: Filter by hierarchy level + schema: + example: BV + enum: + - BV + - LV + - KV + - OV + type: string + - name: division_key + required: false + in: query + description: Filter by division keys + schema: + type: array + items: + type: string + - name: search + required: false + in: query + description: Search name attributes for substring + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindDivisionsResponse' + '401': + description: '' + tags: + - divisions + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/divisions/{divisionId}: + get: + operationId: getDivision + summary: Get division by id + parameters: + - name: divisionId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Division' + '401': + description: '' + '404': + description: '' + tags: + - divisions + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/roles: + get: + operationId: findRoles + summary: Find roles + parameters: + - name: limit + required: false + in: query + schema: + minimum: 1 + default: 20 + type: number + - name: offset + required: false + in: query + schema: + minimum: 0 + type: number + - name: search + required: false + in: query + description: Search term to look for in role name + schema: + type: string + - name: category + required: false + in: query + description: Filter by category id + schema: + type: array + items: + type: string + - name: tag + required: false + in: query + description: Filter by tag id + schema: + type: array + items: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindRolesResponse' + '401': + description: '' + tags: + - roles + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/roles/{roleId}: + get: + operationId: getRole + summary: Get role by id + parameters: + - name: roleId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Role' + '401': + description: '' + '404': + description: '' + tags: + - roles + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/role-tags: + get: + operationId: findRoleTags + summary: Find role tags + parameters: + - name: limit + required: false + in: query + schema: + minimum: 1 + default: 20 + type: number + - name: offset + required: false + in: query + schema: + minimum: 0 + type: number + - name: search + required: false + in: query + description: Search name attribute for substring + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindRoleTagsResponse' + '401': + description: '' + tags: + - roles + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/role-categories: + get: + operationId: findRoleCategories + summary: Find role categories + parameters: + - name: limit + required: false + in: query + schema: + minimum: 1 + default: 20 + type: number + - name: offset + required: false + in: query + schema: + minimum: 0 + type: number + - name: search + required: false + in: query + description: Search name attribute for substring + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindRoleCategoriesResponse' + '401': + description: '' + tags: + - roles + security: + - bearer: [] + - basic: [] + - api_key: [] + /v1/campaigns/pois: + post: + operationId: createPoi + summary: Create a new POI + parameters: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreatePoi' + responses: + '201': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Poi' + '401': + description: '' + tags: + - campaigns + security: + - bearer: [] + - oauth2: [] + get: + operationId: findPois + summary: Find POIs + parameters: + - name: type + required: false + in: query + description: filter by POI type + schema: + example: POSTER + enum: + - FLYER_SPOT + - POSTER + - HOUSE + type: string + - name: bbox + required: false + in: query + schema: + example: '-74.006,40.7128,-73.935242,40.789142' + type: string + - name: agent_id + required: false + in: query + description: Filter by agent id + schema: + example: '1005' + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/FindPoisResponse' + '401': + description: '' + tags: + - campaigns + security: + - bearer: [] + - oauth2: [] + /v1/campaigns/pois/{poiId}: + get: + operationId: getPoi + summary: Get a POI + parameters: + - name: poiId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Poi' + '401': + description: '' + '404': + description: '' + tags: + - campaigns + security: + - bearer: [] + - oauth2: [] + put: + operationId: updatePoi + summary: Update a POI + parameters: + - name: poiId + required: true + in: path + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdatePoi' + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Poi' + '401': + description: '' + '404': + description: '' + tags: + - campaigns + security: + - bearer: [] + - oauth2: [] + delete: + operationId: deletePoi + summary: Delete a POI + parameters: + - name: poiId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Poi' + '401': + description: '' + '404': + description: '' + tags: + - campaigns + security: + - bearer: [] + - oauth2: [] + /v1/campaigns/pois/{poiId}/photos: + post: + operationId: addPoiPhoto + summary: Add POI photo + requestBody: + content: + multipart/form-data: + schema: + type: object + required: + - image + properties: + image: + type: file + parameters: + - name: poiId + required: true + in: path + schema: + type: string + responses: + '201': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Poi' + '401': + description: '' + '404': + description: '' + tags: + - campaigns + security: + - bearer: [] + - oauth2: [] + /v1/campaigns/pois/{poiId}/photos/{photoId}: + delete: + operationId: deletePoiPhoto + summary: Delete a POI Photo + parameters: + - name: poiId + required: true + in: path + schema: + type: string + - name: photoId + required: true + in: path + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Poi' + '401': + description: '' + '404': + description: '' + tags: + - campaigns + security: + - bearer: [] + - oauth2: [] + /health: + get: + tags: + - health + security: [] + description: health check endpoint + responses: + '200': + description: health check response + content: + application/json: + schema: + $ref: '#/components/schemas/HealthCheckResponse' +info: + title: Gruene API + description: > + + ## OpenAPI Endpoints + + OpenAPI Spec in JSON
+ + OpenAPI Spec in YAML
+ + + ### Offboarding + + Every service conntected to Grünes Netz needs to remove users when they are + removed from `saml.gruene.de`. + + Connected services need to pull a list of users waiting for removal at least + once a week. + + api.gruene.de needs to be informed whether the user did not exist or was + removed. + + API tokens can be obtained from `technik@verdigado.com`. + version: 0.1.0 + contact: {} +tags: [] +servers: + - url: https://api.gruene.de + description: Production + - url: http://192.168.178.35:5000 + description: Development +components: + securitySchemes: + basic: + type: http + scheme: basic + bearer: + scheme: bearer + bearerFormat: JWT + type: http + api_key: + type: apiKey + in: header + name: x-api-key + description: Api Key Authentication + schemas: + 'User': + type: object + properties: + id: + type: string + description: The User Id (Sherpa Id) + example: '12345678' + disabled: + type: boolean + description: |- + Flag that indicates if the user is not in sherpa anymore or has no + active memberships. + username: + type: string + description: The users username. Used to log in to Grünes Netz (gnetz username) + example: JohnDoe1 + email: + type: string + description: Main user email address. Used to log in to Grünes Netz (gnetz email) + example: john.doe@example.com + firstName: + type: string + description: User first name + example: John + lastName: + type: string + description: User last name + example: Doe + required: + - id + - username + - email + - firstName + - lastName + FindUsersResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/User' + required: + - data + UserRbacGroup: + type: object + properties: + id: + type: string + description: |- + The group id. + Contains the division id. + example: '2092' + divisionKey: + type: string + description: Division key of the division this group represents. + example: '10100000' + parentKey: + type: string + nullable: true + description: Division key of the parent division if there is one. + example: '10000000' + implicit: + type: boolean + description: >- + Indicate if user has a direct or indirect membership in the + division. + + A indrect membership can be inherited, eg user is member if a KV so + the user is also + + member of the LV/KV, or if the user has a role of a division he is + not part of. + example: true + name: + type: string + description: Name of the Group (division name) + example: Baden-Württemberg + displayName: + type: string + description: Descriptive name of the division. + example: Baden-Württemberg LV + hierarchy: + description: The root hierarchy the division belongs to + example: GR + enum: + - GR + - GJ + - KPV + type: string + level: + description: Level in the hierarchy + example: BV + enum: + - BV + - LV + - KV + - OV + type: string + required: + - id + - divisionKey + - parentKey + - implicit + - name + - displayName + - hierarchy + - level + UserRbacRole: + type: object + properties: + id: + type: string + description: The role id. + example: '6051228' + groupId: + type: string + description: |- + The group id this role refers to. + Contains the division id. + example: '7874541' + divisionKey: + type: string + description: The division key this role refers to. + example: '10206400' + label: + type: string + description: Role name. + example: Kreisverband GR - Mitgliederbeauftragte + required: + - id + - groupId + - divisionKey + - label + UserRbacStructure: + type: object + properties: + userId: + type: string + description: |- + User id + @example: '1234' + groups: + description: List of RBAC groups + type: array + items: + $ref: '#/components/schemas/UserRbacGroup' + roles: + description: List of RBAC roles + type: array + items: + $ref: '#/components/schemas/UserRbacRole' + required: + - userId + - groups + - roles + NbOrganization: + type: object + properties: + id: + type: string + description: Unique character code to identify organization + example: GR + name: + type: string + description: Organization name + example: BÜNDNIS 90/DIE GRÜNEN + regional_chapter_id_prefix: + type: string + description: >- + Division keys belonging to this organization are always beginning + with this sequence. + example: '1' + required: + - id + - name + - regional_chapter_id_prefix + FindNbOrganizationsResponse: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/NbOrganization' + count: + type: number + required: + - items + - count + NbExternalRef: + type: object + properties: + type: + type: string + description: Type of the external ref + example: SHERPA + key: + type: string + description: Id in the external system + example: '12345678' + required: + - type + - key + NbGroup: + type: object + properties: + name: + type: string + example: BAG Demokratie und Recht + slug: + type: string + example: BAG_DEMOKRATIE_RECHT + type: + type: string + example: WORKGROUP + active: + type: boolean + example: true + level: + type: string + example: DE:BUNDESVERBAND + organization: + $ref: '#/components/schemas/NbOrganization' + external_refs: + type: array + items: + $ref: '#/components/schemas/NbExternalRef' + required: + - name + - slug + - type + - active + - level + - organization + - external_refs + FindNbGroupsResponse: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/NbGroup' + required: + - items + NbRegionalChapter: + type: object + properties: + id: + type: string + description: Id of the regional chapter (division key) + example: '11004410' + name: + type: string + description: Regional chapter name + example: Neunkirchen-Seelscheid + type: + description: |- + Regional chapter type + Possible values: BV | LV | KV | OV + example: OV + enum: + - BV + - LV + - KV + - OV + type: string + organization: + $ref: '#/components/schemas/NbOrganization' + zip_code: + type: string + description: Zip code of office location + example: '53819' + required: + - id + - name + - type + - organization + - zip_code + FindNbRegionalChaptersResponse: + type: object + properties: + count: + type: number + items: + type: array + items: + $ref: '#/components/schemas/NbRegionalChapter' + required: + - count + - items + ImageLink: + type: object + properties: + url: + type: string + description: Image url + example: >- + https://static.example.com/profiles/10b4be70-9e3d-40a5-a46a-b0668bdf7e03.jpg + mimetype: + type: string + description: Image mimetype + example: image/jpeg + width: + type: number + description: Width in pixels + example: 150 + minimum: 0 + height: + type: number + description: Height in pixels + example: 150 + minimum: 0 + required: + - url + - mimetype + - width + - height + ProfileImage: + type: object + properties: + thumbnail: + $ref: '#/components/schemas/ImageLink' + large: + $ref: '#/components/schemas/ImageLink' + required: + - thumbnail + - large + PhoneNumberEntry: + type: object + properties: + id: + type: string + example: '123' + country: + type: string + description: Country code in german format + example: '0049' + number: + type: string + description: Phone number + example: '177234512345' + required: + - id + - country + - number + MessengerEntry: + type: object + properties: + id: + type: string + example: '123' + type: + type: string + example: threema + enum: + - threema + externalId: + type: string + example: 822d7a5a + required: + - id + - type + - externalId + SocialMediaEntry: + type: object + properties: + id: + type: string + example: '123' + type: + description: Type of social media entry + example: mastodon + enum: + - facebook + - instagram + - mastodon + - twitter + - chatbegruenung + type: string + url: + type: string + description: Url to the platform account + example: https://mastodon.online/@saxgruen + required: + - id + - type + - url + ProfileTag: + type: object + properties: + id: + type: string + description: Tag id + example: '1' + type: + description: Tag type + example: '"interest' + enum: + - skill + - interest + type: string + label: + type: string + description: Tag label + example: Zeitpolitik + externalId: + type: string + description: External id + example: '100' + required: + - id + - type + - label + Address: + type: object + properties: + city: + type: string + description: Location city + example: Berlin + zip: + type: string + description: Location zip code + example: '10176' + line1: + type: string + description: First address line for street and house number + example: Bahnhofstr. 5 + required: + - city + - zip + - line1 + DivisionEmail: + type: object + properties: + tags: + description: Tags associated with email as string values + example: + - BV-GRÜNE-Info + type: array + items: + type: string + purposes: + description: Purposes associated with email + examples: + - - privat + - - grüne + - - dienstlich + - - Postanschrift + - - Rechnungsanschrift + - - Lieferanschrift + type: array + items: + type: string + address: + type: string + description: Email address + example: john.doe@example.com + isFavorite: + type: boolean + description: Indicate if this email is preferred for general inquiries + example: false + required: + - tags + - purposes + - address + - isFavorite + Division: + type: object + properties: + urls: + description: List of internet presences + example: + - https://example.com + type: array + items: + type: string + id: + type: string + description: The division id + example: '123' + divisionKey: + type: string + description: The division key + example: '10000000' + name1: + type: string + example: Landesverband + name2: + type: string + example: Baden-Württemberg + shortName: + type: string + description: Descriptive name of the division. + example: Baden-Württemberg LV + hierarchy: + type: object + description: The root hierarchy the division belongs to + example: GR + level: + description: Level in the hierarchy + example: BV + enum: + - BV + - LV + - KV + - OV + type: string + officeAddress: + nullable: true + description: Office address + allOf: + - $ref: '#/components/schemas/Address' + emails: + description: Email Addresses + type: array + items: + $ref: '#/components/schemas/DivisionEmail' + required: + - urls + - id + - divisionKey + - name1 + - name2 + - shortName + - hierarchy + - level + - officeAddress + - emails + DivisionMembership: + type: object + properties: + division: + $ref: '#/components/schemas/Division' + joinedAt: + format: date-time + type: string + required: + - division + - joinedAt + ProfileRole: + type: object + properties: + id: + type: string + example: '12345' + type: + example: role + enum: + - role + - mandate + - office + type: string + name: + type: string + example: LAG Verkehr Mitarbeitende + alias: + type: string + example: LAG Mobilität + required: + - id + - type + - name + - alias + PublicProfile: + type: object + properties: + id: + type: string + example: 71eb2937-12f2-4483-906a-f01a972afecf + userId: + type: string + description: User id (Sherpa user id) + example: '12345678' + personalId: + type: string + description: personal identification number + example: '12345678' + username: + type: string + example: JohnDoe1 + firstName: + type: string + example: John + lastName: + type: string + example: Doe + image: + $ref: '#/components/schemas/ProfileImage' + phoneNumbers: + type: array + items: + $ref: '#/components/schemas/PhoneNumberEntry' + messengers: + type: array + items: + $ref: '#/components/schemas/MessengerEntry' + socialMedia: + type: array + items: + $ref: '#/components/schemas/SocialMediaEntry' + tags: + type: array + items: + $ref: '#/components/schemas/ProfileTag' + joinedAt: + format: date-time + type: string + description: First entry date in the BV + memberships: + type: array + items: + $ref: '#/components/schemas/DivisionMembership' + roles: + type: array + items: + $ref: '#/components/schemas/ProfileRole' + achievements: + example: + - Silberne Sonnenblume + type: array + items: + type: string + email: + type: string + example: john.doe@example.com + required: + - id + - userId + - personalId + - username + - firstName + - lastName + - phoneNumbers + - messengers + - socialMedia + - tags + - roles + - achievements + FindProfilesResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/PublicProfile' + meta: + type: object + properties: + count: + required: true + type: number + offset: + required: true + type: number + limit: + required: true + type: number + hasNext: + required: true + type: boolean + required: + - data + - meta + CreateProfile: + type: object + properties: + userId: + type: string + required: + - userId + ProfilePrivacySettings: + type: object + properties: + overall: + example: BV_WIDE + enum: + - PRIVATE + - PUBLIC + - BV_WIDE + - LV_WIDE + - KV_WIDE + - OV_WIDE + type: string + email: + example: PRIVATE + enum: + - PRIVATE + - PUBLIC + - BV_WIDE + - LV_WIDE + - KV_WIDE + - OV_WIDE + type: string + chatbegruenung: + example: PUBLIC + enum: + - PRIVATE + - PUBLIC + - BV_WIDE + - LV_WIDE + - KV_WIDE + - OV_WIDE + type: string + required: + - overall + - email + - chatbegruenung + Profile: + type: object + properties: + id: + type: string + example: 71eb2937-12f2-4483-906a-f01a972afecf + userId: + type: string + description: User id (Sherpa user id) + example: '12345678' + personalId: + type: string + description: personal identification number + example: '12345678' + username: + type: string + example: JohnDoe1 + firstName: + type: string + example: John + lastName: + type: string + example: Doe + email: + type: string + example: john.doe@example.com + image: + $ref: '#/components/schemas/ProfileImage' + phoneNumbers: + type: array + items: + $ref: '#/components/schemas/PhoneNumberEntry' + messengers: + type: array + items: + $ref: '#/components/schemas/MessengerEntry' + socialMedia: + type: array + items: + $ref: '#/components/schemas/SocialMediaEntry' + tags: + type: array + items: + $ref: '#/components/schemas/ProfileTag' + joinedAt: + format: date-time + type: string + description: First entry date in the BV + memberships: + type: array + items: + $ref: '#/components/schemas/DivisionMembership' + roles: + type: array + items: + $ref: '#/components/schemas/ProfileRole' + achievements: + example: + - Silberne Sonnenblume + type: array + items: + type: string + privacy: + $ref: '#/components/schemas/ProfilePrivacySettings' + required: + - id + - userId + - personalId + - username + - firstName + - lastName + - email + - phoneNumbers + - messengers + - socialMedia + - tags + - roles + - achievements + - privacy + UpdatePhoneNumber: + type: object + properties: + country: + type: string + description: Country code in german format + example: '0049' + number: + type: string + description: Phone number + example: '177234512345' + id: + type: string + example: '123' + required: + - country + - number + UpdateMessengerEntry: + type: object + properties: + type: + type: string + example: threema + enum: + - threema + externalId: + type: string + example: 822d7a5a + id: + type: string + example: '123' + required: + - type + - externalId + UpdateSocialMediaEntry: + type: object + properties: + type: + type: string + description: Type of social media entry + example: mastodon + enum: + - facebook + - instagram + - mastodon + - twitter + - chatbegruenung + url: + type: string + description: Url to the platform account + example: https://mastodon.online/@saxgruen + id: + type: string + example: '123' + required: + - type + - url + UpdateProfile: + type: object + properties: + email: + type: string + example: john.doe2@example.com + phoneNumbers: + type: array + items: + $ref: '#/components/schemas/UpdatePhoneNumber' + messengers: + type: array + items: + $ref: '#/components/schemas/UpdateMessengerEntry' + socialMedia: + type: array + items: + $ref: '#/components/schemas/UpdateSocialMediaEntry' + tags: + description: List of external tag ids + example: + - '501' + - '14003317' + type: array + items: + type: string + privacy: + $ref: '#/components/schemas/ProfilePrivacySettings' + required: + - email + - phoneNumbers + - messengers + - socialMedia + - tags + - privacy + FindProfileTagsResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/ProfileTag' + meta: + type: object + properties: + count: + required: true + type: number + total: + required: true + type: number + offset: + required: true + type: number + limit: + required: true + type: number + required: + - data + - meta + OffboardingUserInfo: + type: object + properties: + id: + type: string + description: The User Id (Sherpa Id) + example: '12345678' + username: + type: string + description: The users username. Used to log in to Grünes Netz (gnetz username) + example: JohnDoe1 + email: + type: string + description: The users email address. + example: john.doe@example.com + required: + - id + - username + FindOffboardingUsersResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/OffboardingUserInfo' + meta: + type: object + properties: + cursorNext: + required: false + type: string + required: + - data + - meta + UpsertOffboardingServiceUser: + type: object + properties: + id: + type: string + description: The user's id. + example: '12345678' + status: + enum: + - deleted + - not_found + - anonymized + type: string + required: + - id + - status + BatchUpdateOffboardingServiceUsers: + type: object + properties: + upsert: + type: array + items: + $ref: '#/components/schemas/UpsertOffboardingServiceUser' + FindDivisionsResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Division' + meta: + type: object + properties: + count: + required: true + type: number + total: + required: true + type: number + offset: + required: true + type: number + limit: + required: true + type: number + required: + - data + - meta + RoleAlias: + type: object + properties: + id: + type: string + description: Id of the role alias + example: '503' + label: + type: string + description: Label of the alias + divisionId: + type: string + description: Division id where this alias applies + example: '2092' + divisionKey: + type: string + description: Division key where this alias applies + example: '10100000' + required: + - id + - label + - divisionId + - divisionKey + RoleCategory: + type: object + properties: + id: + type: string + description: The role category id + example: '84' + label: + type: string + description: Name of the role category + aliases: + description: Role category aliases + type: array + items: + $ref: '#/components/schemas/RoleAlias' + required: + - id + - label + - aliases + RoleTag: + type: object + properties: + id: + type: string + description: Id of the role tag + example: '6590132' + name: + type: string + description: Name of the role tag + required: + - id + - name + Role: + type: object + properties: + id: + type: string + description: The role id + example: '123' + name: + type: string + description: Name of the role + hierarchy: + description: Hierarchy this role refers to + example: GR + enum: + - GR + - GJ + - KPV + type: string + type: + description: Type of role + example: ROLLE + enum: + - AMT + - BEZ + - MANDAT + - ROLLE + - SYSTEM + type: string + minAge: + type: number + nullable: true + description: Role min age + example: 0 + maxAge: + type: number + description: Role max age + example: 99 + level: + description: Hierarchy level this role applies to + example: LV + enum: + - ALL + - BV + - LV + - KV + - OV + - BEZV + type: string + categories: + description: Role categories + type: array + items: + $ref: '#/components/schemas/RoleCategory' + tags: + description: Role tags + type: array + items: + $ref: '#/components/schemas/RoleTag' + aliases: + description: Role Aliases + type: array + items: + $ref: '#/components/schemas/RoleAlias' + required: + - id + - name + - hierarchy + - type + - minAge + - maxAge + - level + - categories + - tags + - aliases + FindRolesResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Role' + meta: + type: object + properties: + count: + required: true + type: number + total: + required: true + type: number + offset: + required: true + type: number + limit: + required: true + type: number + required: + - data + - meta + FindRoleTagsResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/RoleTag' + meta: + type: object + properties: + count: + required: true + type: number + total: + required: true + type: number + offset: + required: true + type: number + limit: + required: true + type: number + required: + - data + - meta + FindRoleCategoriesResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/RoleCategory' + meta: + type: object + properties: + count: + required: true + type: number + total: + required: true + type: number + offset: + required: true + type: number + limit: + required: true + type: number + required: + - data + - meta + PoiAddress: + type: object + properties: + city: + type: string + description: Location city + example: Berlin + zip: + type: string + description: Location zip code + example: '10176' + street: + type: string + description: First address line for street and house number + example: Bahnhofstraße + houseNumber: + type: string + description: First address line for street and house number + example: 12/a + required: + - city + - zip + - street + - houseNumber + PoiPoster: + type: object + properties: + status: + description: Current status of the poster. + example: OK + enum: + - OK + - DAMAGED + - REMOVED + - MISSING + type: string + comment: + type: string + nullable: true + description: A short text to describe the state of the poster. + example: Poster was sprayed with graffiti. + required: + - status + - comment + PoiFlyerSpot: + type: object + properties: + flyerCount: + type: number + description: Number of flyers on this spot. + minimum: 0 + required: + - flyerCount + PoiHouse: + type: object + properties: + countOpenedDoors: + type: number + description: Number of apartment doors that were opened for a conversation. + minimum: 0 + countClosedDoors: + type: number + description: Number of appartment doors that remained closed. + minimum: 0 + required: + - countOpenedDoors + - countClosedDoors + UpdatePoi: + type: object + properties: + address: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiAddress' + poster: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiPoster' + flyerSpot: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiFlyerSpot' + house: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiHouse' + CreatePoi: + type: object + properties: + coords: + description: Coordinates represented in GeoJSON [longitude, latitude] + example: + - 120.123 + - -35.456 + minItems: 2 + maxItems: 2 + type: array + items: + type: number + type: + enum: + - FLYER_SPOT + - POSTER + - HOUSE + type: string + address: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiAddress' + poster: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiPoster' + flyerSpot: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiFlyerSpot' + house: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiHouse' + required: + - coords + - type + Image: + type: object + properties: + id: + type: string + type: + type: string + description: Image url + example: thumbnail + url: + type: string + description: Image url + example: >- + https://static.example.com/profiles/10b4be70-9e3d-40a5-a46a-b0668bdf7e03.jpg + mimetype: + type: string + description: Image mimetype + example: image/jpeg + width: + type: number + description: Width in pixels + example: 150 + height: + type: number + description: Height in pixels + example: 150 + required: + - id + - url + - mimetype + - width + - height + ImageSrcSet: + type: object + properties: + id: + type: string + original: + $ref: '#/components/schemas/Image' + srcset: + type: array + items: + $ref: '#/components/schemas/Image' + required: + - id + - original + - srcset + Poi: + type: object + properties: + coords: + description: Coordinates represented in GeoJSON [longitude, latitude] + example: + - 120.123 + - -35.456 + minItems: 2 + maxItems: 2 + type: array + items: + type: number + id: + type: string + example: '1' + agentId: + type: string + divisionKey: + type: string + createdAt: + format: date-time + type: string + photos: + type: array + items: + $ref: '#/components/schemas/ImageSrcSet' + address: + nullable: true + allOf: + - $ref: '#/components/schemas/PoiAddress' + type: + enum: + - FLYER_SPOT + - POSTER + - HOUSE + type: string + poster: + $ref: '#/components/schemas/PoiPoster' + flyerSpot: + $ref: '#/components/schemas/PoiFlyerSpot' + house: + $ref: '#/components/schemas/PoiHouse' + required: + - coords + - id + - agentId + - divisionKey + - createdAt + - photos + - address + - type + FindPoisResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Poi' + required: + - data + HealthCheckResponse: + type: object + properties: + status: + type: string + example: error + info: + type: object + additionalProperties: + type: object + required: + - status + properties: + status: + type: string + enum: + - up + - down + example: + memory_heap: + status: up + ldap: + status: up + sherpa: + status: up + error: + type: object + additionalProperties: + type: object + required: + - status + properties: + status: + type: string + enum: + - up + - down + message: + type: string + example: + keycloak: + status: down + example: client not authenticated + details: + type: object + additionalProperties: + type: object + required: + - status + properties: + status: + type: string + enum: + - up + - down + message: + type: string + example: + memory_heap: + status: up + ldap: + status: up + sherpa: + status: up + keycloak: + status: down + example: client not authenticated