Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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: 0 additions & 8 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
<!--
Thanks for contributing!

Provide a description of your changes below and a general summary in the title

Please look at the following checklist to ensure that your PR can be accepted quickly:
-->

## Status

**READY/IN DEVELOPMENT/HOLD**
Expand Down
11 changes: 0 additions & 11 deletions lib/src/config/app_dependencies.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ class AppDependencies {
late final DataRepository<UserContentPreferences>
userContentPreferencesRepository;
late final DataRepository<RemoteConfig> remoteConfigRepository;
late final DataRepository<LocalAd> localAdRepository;
late final EmailRepository emailRepository;

// Services
Expand Down Expand Up @@ -232,16 +231,6 @@ class AppDependencies {

emailRepository = EmailRepository(emailClient: emailClient);

final localAdClient = DataMongodb<LocalAd>(
connectionManager: _mongoDbConnectionManager,
modelName: 'local_ads',
fromJson: LocalAd.fromJson,
toJson: LocalAd.toJson,
searchableFields: ['title'],
logger: Logger('DataMongodb<LocalAd>'),
);
localAdRepository = DataRepository(dataClient: localAdClient);

// 5. Initialize Services
tokenBlacklistService = MongoDbTokenBlacklistService(
connectionManager: _mongoDbConnectionManager,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'package:flutter_news_app_api_server_full_source_code/src/database/migration.dart';
import 'package:logging/logging.dart';
import 'package:mongo_dart/mongo_dart.dart';

/// Migration to remove the legacy `local` ad platform from the `remote_configs`
/// collection.
///
/// This migration performs two critical cleanup tasks:
/// 1. It removes the `local` key from the `adConfig.platformAdIdentifiers` map
/// in all `remote_configs` documents.
/// 2. It updates any `remote_configs` document where the `primaryAdPlatform`
/// is set to `local`, changing it to `admob`.
///
/// This ensures data consistency after the removal of the `AdPlatformType.local`
/// enum value and prevents deserialization errors in the application.
class RemoveLocalAdPlatform extends Migration {
/// {@macro remove_local_ad_platform}
RemoveLocalAdPlatform()
: super(
prDate: '20251103073226',
prId: '57',
prSummary:
'Removes the legacy local ad platform from the remote config, migrating existing data to use admob as the default.',
);

@override
Future<void> up(Db db, Logger log) async {
final collection = db.collection('remote_configs');

// Step 1: Unset the 'local' key from the platformAdIdentifiers map.
// This removes the field entirely from any document where it exists.
log.info(
'Attempting to remove "adConfig.platformAdIdentifiers.local" field...',
);
final unsetResult = await collection.updateMany(
where.exists('adConfig.platformAdIdentifiers.local'),
modify.unset('adConfig.platformAdIdentifiers.local'),
);
log.info(
'Removed "adConfig.platformAdIdentifiers.local" from ${unsetResult.nModified} documents.',
);

// Step 2: Update the primaryAdPlatform from 'local' to 'admob'.
// This ensures that no document is left with an invalid primary platform.
log.info(
'Attempting to migrate primaryAdPlatform from "local" to "admob"...',
);
final updateResult = await collection.updateMany(
where.eq('adConfig.primaryAdPlatform', 'local'),
modify.set('adConfig.primaryAdPlatform', 'admob'),
);
log.info(
'Migrated primaryAdPlatform to "admob" for ${updateResult.nModified} documents.',
);
}

@override
Future<void> down(Db db, Logger log) async {
// Reverting this change is not safe as it would require re-introducing
// an enum value that no longer exists in the code.
log.warning(
'Reverting "RemoveLocalAdPlatform" is not supported. The "local" ad platform configuration would need to be manually restored if required.',
);
}
}
2 changes: 2 additions & 0 deletions lib/src/database/migrations/all_migrations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter_news_app_api_server_full_source_code/src/database/migrat
import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251013000056_add_saved_filters_to_user_preferences.dart';
import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251013000057_add_saved_filters_to_remote_config.dart';
import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251024000000_add_logo_url_to_sources.dart';
import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251103073226_remove_local_ad_platform.dart';
import 'package:flutter_news_app_api_server_full_source_code/src/services/database_migration_service.dart'
show DatabaseMigrationService;

Expand All @@ -16,4 +17,5 @@ final List<Migration> allMigrations = [
AddSavedFiltersToUserPreferences(),
AddSavedFiltersToRemoteConfig(),
AddLogoUrlToSources(),
RemoveLocalAdPlatform(),
];
22 changes: 5 additions & 17 deletions lib/src/registry/data_operation_registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ typedef ItemUpdater =
typedef ItemDeleter =
Future<void> Function(RequestContext context, String id, String? userId);

final _log = Logger('DataOperationRegistry');

/// {@template data_operation_registry}
/// A centralized registry for all data handling functions (CRUD operations).
///
Expand All @@ -56,12 +58,12 @@ typedef ItemDeleter =
/// data operations are performed for each model, improving consistency across
/// the API.
/// {@endtemplate}

final _log = Logger('DataOperationRegistry');

class DataOperationRegistry {
/// {@macro data_operation_registry}
DataOperationRegistry() {
_log.info(
'Initializing DataOperationRegistry.',
);
_registerOperations();
}

Expand Down Expand Up @@ -113,8 +115,6 @@ class DataOperationRegistry {
.read(id: id, userId: null),
'remote_config': (c, id) =>
c.read<DataRepository<RemoteConfig>>().read(id: id, userId: null),
'local_ad': (c, id) =>
c.read<DataRepository<LocalAd>>().read(id: id, userId: null),
'dashboard_summary': (c, id) =>
c.read<DashboardSummaryService>().getSummary(),
});
Expand Down Expand Up @@ -166,9 +166,6 @@ class DataOperationRegistry {
sort: s,
pagination: p,
),
'local_ad': (c, uid, f, s, p) => c
.read<DataRepository<LocalAd>>()
.readAll(userId: uid, filter: f, sort: s, pagination: p),
});

// --- Register Item Creators ---
Expand Down Expand Up @@ -196,10 +193,6 @@ class DataOperationRegistry {
'remote_config': (c, item, uid) => c
.read<DataRepository<RemoteConfig>>()
.create(item: item as RemoteConfig, userId: uid),
'local_ad': (c, item, uid) => c.read<DataRepository<LocalAd>>().create(
item: item as LocalAd,
userId: uid,
),
});

// --- Register Item Updaters ---
Expand Down Expand Up @@ -319,9 +312,6 @@ class DataOperationRegistry {
'remote_config': (c, id, item, uid) => c
.read<DataRepository<RemoteConfig>>()
.update(id: id, item: item as RemoteConfig, userId: uid),
'local_ad': (c, id, item, uid) => c
.read<DataRepository<LocalAd>>()
.update(id: id, item: item as LocalAd, userId: uid),
});

// --- Register Item Deleters ---
Expand All @@ -343,8 +333,6 @@ class DataOperationRegistry {
.delete(id: id, userId: uid),
'remote_config': (c, id, uid) =>
c.read<DataRepository<RemoteConfig>>().delete(id: id, userId: uid),
'local_ad': (c, id, uid) =>
c.read<DataRepository<LocalAd>>().delete(id: id, userId: uid),
});
}
}
30 changes: 0 additions & 30 deletions lib/src/registry/model_registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -425,36 +425,6 @@ final modelRegistry = <String, ModelConfig<dynamic>>{
requiresAuthentication: true,
),
),
'local_ad': ModelConfig<LocalAd>(
fromJson: LocalAd.fromJson,
getId: (ad) => ad.id,
getOwnerId: null, // LocalAd is a global resource, not user-owned
getCollectionPermission: const ModelActionPermission(
type: RequiredPermissionType.specificPermission,
permission: Permissions.localAdRead,
requiresAuthentication: true,
),
getItemPermission: const ModelActionPermission(
type: RequiredPermissionType.specificPermission,
permission: Permissions.localAdRead,
requiresAuthentication: true,
),
postPermission: const ModelActionPermission(
type: RequiredPermissionType.adminOnly,
permission: Permissions.localAdCreate,
requiresAuthentication: true,
),
putPermission: const ModelActionPermission(
type: RequiredPermissionType.adminOnly,
permission: Permissions.localAdUpdate,
requiresAuthentication: true,
),
deletePermission: const ModelActionPermission(
type: RequiredPermissionType.adminOnly,
permission: Permissions.localAdDelete,
requiresAuthentication: true,
),
),
};

/// Type alias for the ModelRegistry map for easier provider usage.
Expand Down
16 changes: 1 addition & 15 deletions lib/src/services/database_seeding_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,6 @@ class DatabaseSeedingService {
getId: (item) => item.id,
toJson: (item) => item.toJson(),
);
await _seedCollection<LocalAd>(
collectionName: 'local_ads',
fixtureData: localAdsFixturesData,
getId: (ad) => ad.id,
// ignore: unnecessary_lambdas
toJson: (item) => LocalAd.toJson(item),
);

_log.info('Database seeding process completed.');
}
Expand Down Expand Up @@ -130,7 +123,7 @@ class DatabaseSeedingService {
// Ensure primaryAdPlatform is not 'demo' for initial setup
// since its not intended for any use outside the mobile client.
final productionReadyAdConfig = initialConfig.adConfig.copyWith(
primaryAdPlatform: AdPlatformType.local,
primaryAdPlatform: AdPlatformType.admob,
);

final productionReadyConfig = initialConfig.copyWith(
Expand Down Expand Up @@ -191,13 +184,6 @@ class DatabaseSeedingService {
.collection('countries')
.createIndex(keys: {'name': 1}, name: 'countries_name_index');

/// Index for searching local ads by adType.
/// This index supports efficient queries and filtering on the 'adType' field
/// of local ad documents.
await _db
.collection('local_ads')
.createIndex(keys: {'adType': 1}, name: 'local_ads_adType_index');

// --- TTL and Unique Indexes via runCommand ---
// The following indexes are created using the generic `runCommand` because
// they require specific options not exposed by the simpler `createIndex`
Expand Down
12 changes: 6 additions & 6 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ packages:
dependency: transitive
description:
name: analyzer
sha256: a40a0cee526a7e1f387c6847bd8a5ccbf510a75952ef8a28338e989558072cb0
sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08
url: "https://pub.dev"
source: hosted
version: "8.4.0"
version: "8.4.1"
archive:
dependency: transitive
description:
Expand Down Expand Up @@ -117,8 +117,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "v1.3.1"
resolved-ref: a03efff11b7577974cb444a1a6a46fee8b05ea42
ref: e7c808c9d459233196e2eac3137a9c87d3976af3
resolved-ref: e7c808c9d459233196e2eac3137a9c87d3976af3
url: "https://github.com/flutter-news-app-full-source-code/core.git"
source: git
version: "1.3.1"
Expand All @@ -142,10 +142,10 @@ packages:
dependency: "direct main"
description:
name: dart_frog
sha256: "0fc909d10ae79dd069e6a3a4769aeaa9839c93b7f6f1e71cfd37b276410875e7"
sha256: "87b5280b029aa2f80f5e9954db4b6c7cbbc2ae6adf5579150c11c40829f95a0a"
url: "https://pub.dev"
source: hosted
version: "1.2.4"
version: "1.2.5"
dart_jsonwebtoken:
dependency: "direct main"
description:
Expand Down
5 changes: 5 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,8 @@ dev_dependencies:
test: ^1.25.5
very_good_analysis: ^9.0.0

dependency_overrides:
core:
git:
url: https://github.com/flutter-news-app-full-source-code/core.git
ref: e7c808c9d459233196e2eac3137a9c87d3976af3
5 changes: 0 additions & 5 deletions routes/_middleware.dart
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,6 @@ Handler middleware(Handler handler) {
(_) => deps.remoteConfigRepository,
),
)
.use(
provider<DataRepository<LocalAd>>(
(_) => deps.localAdRepository,
),
)
.use(provider<EmailRepository>((_) => deps.emailRepository))
.use(
provider<TokenBlacklistService>(
Expand Down
Loading