Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .claude/commands/prepare-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ Run:
```
git log --oneline <current_version_tag>..HEAD
```
or if tags are not present, compare with `main`:
or if tags are not present, compare with `origin/main`:
```
git log --oneline main..HEAD
git log --oneline origin/main..HEAD
```
Read the commit messages to understand what changed. Ignore pure chore/refactor commits
(e.g. CLAUDE.md updates, code generation runs) unless they are meaningful to library consumers.
Expand Down Expand Up @@ -61,7 +61,9 @@ Rules:
Stage only `pubspec.yaml` and `CHANGELOG.md`, then commit:
```
git add pubspec.yaml CHANGELOG.md
git commit -m "chore: bump version to <version> and update changelog"
git commit -m "chore: bump version to <version> and update changelog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
```

### 6. Push and open PR
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 3.6.24

- Added `graphqlIdFragment` and `graphqlUuidFragment` static constants to `Access` for GraphQL queries.
- Added `save()` and `delete()` methods to `AccessInput` with full GraphQL mutation support (both ID and UUID variants).
- Updated `Poi.graphqlFragment` to include the `access` field using the UUID access fragment.

## 3.6.23

- CI issues, no code changes.
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,4 @@ Each test file typically tests:

- "wrap it up" - Means review the changes, commit and push, and create a pull request if the user wants
- Do not include Test plan on the PR body under any circumstances, the code should be tested before the PR.
- Always include `Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>` as a footer in every git commit message.
1 change: 1 addition & 0 deletions lib/src/access/access.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ library;

import 'package:collection/collection.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:layrz_logging/layrz_logging.dart';
import 'package:layrz_models/layrz_models.dart';

part 'access.freezed.dart';
Expand Down
8 changes: 4 additions & 4 deletions lib/src/access/access.freezed.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 28 additions & 1 deletion lib/src/access/src/access.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
part of '../access.dart';

@freezed

/// AccessPermission
/// Access Permission class
abstract class Access with _$Access {
const Access._();

const factory Access({
required String id,
String? label,
Expand All @@ -18,4 +19,30 @@ abstract class Access with _$Access {
}) = _Access;

factory Access.fromJson(Map<String, dynamic> json) => _$AccessFromJson(json);

/// [graphqlIdFragment] GraphQL fragment for Access
static const String graphqlIdFragment = '''
fragment accessFragment on AccessPermission {
id
read
write
manage
objectId
userId
module
}
''';

/// [graphqlUuidFragment] GraphQL fragment for Access using UUID
static const String graphqlUuidFragment = '''
fragment accessUuidFragment on AccessPermissionUuid {
id
read
write
manage
objectId
userId
module
}
''';
}
163 changes: 163 additions & 0 deletions lib/src/access/src/access_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ part of '../access.dart';

@unfreezed
abstract class AccessInput with _$AccessInput {
const AccessInput._();
factory AccessInput({
/// Represents the id of the access.
String? id,
Expand All @@ -26,4 +27,166 @@ abstract class AccessInput with _$AccessInput {
}) = _AccessInput;

factory AccessInput.fromJson(Map<String, dynamic> json) => _$AccessInputFromJson(json);

/// [save] saves the access input to the server
/// It returns a [bool] indicating whether the save was successful
Future<bool> save({
/// [apiToken] is the API token to use for authentication. You can get one using the `login` mutation
/// on the GraphQL API.
required String apiToken,

/// [uri] is the GraphQL endpoint to use
required Uri uri,

/// [onResponse] is the callback to call when the response is received
void Function(String statusCode)? onResponse,

/// [useUuid] whether to use UUID for deletion
bool useUuid = false,
}) async {
final connector = LayrzConnector(uri: uri);
try {
final response = await connector.perform(
query: id == null
? (useUuid ? AccessInput.addUuidGraphqlMutation : AccessInput.addIdGraphqlMutation)
: (useUuid ? AccessInput.editUuidGraphqlMutation : AccessInput.editIdGraphqlMutation),
variables: {'apiToken': apiToken, 'data': toJson()},
);

final data = response.data;
if (data == null) {
onResponse?.call('INTERNAL_ERROR');
Log.error("layrz_models/AccessInput/save(): No response from server");
return false;
}

final result = id == null
? (useUuid ? data['data']['addAccessPermissionUuid'] : data['data']['addAccessPermission'])
: (useUuid ? data['data']['editAccessPermissionUuid'] : data['data']['editAccessPermission']);
if (result == null) {
onResponse?.call('INTERNAL_ERROR');
Log.error("layrz_models/AccessInput/save(): No result from server");
return false;
}

if (result['status'] != 'OK') {
onResponse?.call(result['status']);
return false;
}

return true;
} catch (e, stack) {
Log.critical("layrz_models/AccessInput/save(): General exception => $e\n$stack");
return false;
}
}

/// [delete] delete AccessPermission from the server
Future<bool> delete({
/// [apiToken] is the API token to use for authentication. You can get one using the `login` mutation
/// on the GraphQL API.
required String apiToken,

/// [uri] is the GraphQL endpoint to use
required Uri uri,

/// [onResponse] is the callback to call when the response is received
void Function(String statusCode)? onResponse,

/// [useUuid] whether to use UUID for deletion
bool useUuid = false,
}) async {
final connector = LayrzConnector(uri: uri);

try {
final response = await connector.perform(
query: useUuid ? AccessInput.deleteUuidGraphqlMutation : AccessInput.deleteIdGraphqlMutation,
variables: {'apiToken': apiToken, 'data': toJson()},
);

final data = response.data;
if (data == null) {
onResponse?.call('INTERNAL_ERROR');
Log.error("layrz_models/Access/delete(): No response from server");
return false;
}

final result = data['data'][useUuid ? 'deleteAccessPermissionUuid' : 'deleteAccessPermission'];
if (result == null) {
onResponse?.call('INTERNAL_ERROR');
Log.error("layrz_models/Access/delete(): No result from server");
return false;
}

if (result['status'] != 'OK') {
onResponse?.call(result['status']);
return false;
}

return true;
} catch (e, stack) {
Log.critical("layrz_models/Access/delete(): General exception => $e\n$stack");
return false;
}
}

/// [addIdGraphqlMutation] GraphQL mutation for adding an access permission
static String get addIdGraphqlMutation => r'''
mutation($apiToken: String!, $data: AccessPermissionInput!) {
addAccessPermission(apiToken: $apiToken, data: $data) {
status
errors
}
}
''';

/// [addUuidGraphqlMutation] GraphQL mutation for adding an access permission
static String get addUuidGraphqlMutation => r'''
mutation($apiToken: String!, $data: AccessPermissionUuidInput!) {
addAccessPermissionUuid(apiToken: $apiToken, data: $data) {
status
errors
}
}
''';

/// [editIdGraphqlMutation] GraphQL mutation for updating an access permission
static String get editIdGraphqlMutation => r'''
mutation($apiToken: String!, $data: AccessPermissionInput!) {
editAccessPermission(apiToken: $apiToken, data: $data) {
status
errors
}
}
''';

/// [editUuidGraphqlMutation] GraphQL mutation for updating an access permission
static String get editUuidGraphqlMutation => r'''
mutation($apiToken: String!, $data: AccessPermissionUuidInput!) {
editAccessPermissionUuid(apiToken: $apiToken, data: $data) {
status
errors
}
}
''';

/// [deleteIdGraphqlMutation] GraphQL mutation for deleting an access permission
static String get deleteIdGraphqlMutation => r'''
mutation($apiToken: String!, $data: AccessPermissionInput!) {
deleteAccessPermission(apiToken: $apiToken, data: $data) {
status
errors
}
}
''';

/// [deleteUuidGraphqlMutation] GraphQL mutation for deleting an access permission
static String get deleteUuidGraphqlMutation => r'''
mutation($apiToken: String!, $data: AccessPermissionUuidInput!) {
deleteAccessPermissionUuid(apiToken: $apiToken, data: $data) {
status
errors
}
}
''';
}
8 changes: 7 additions & 1 deletion lib/src/map/src/poi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,20 @@ abstract class Poi with _$Poi {

/// [graphqlFragment] is the GraphQL fragment to fetch the POI data
/// It includes the basic user fields fragment [basicUserFields] to get the user data
static String get graphqlFragment => '''
static String get graphqlFragment =>
'''
${Access.graphqlUuidFragment}
fragment poiFragment on Poi {
id
name
description
icon
latitude
longitude

access {
...accessUuidFragment
}
}
''';

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
description: Layrz API models for Dart/Flutter. This package contains the models used by the Layrz API.
name: layrz_models
version: "3.6.23"
version: "3.6.24"
repository: https://github.com/goldenm-software/layrz_models

environment:
Expand Down
Loading