[mob][photos] Add guards to make sure no email is linked to more than one person

This commit is contained in:
ashilkn
2025-01-23 20:44:43 +05:30
parent f11d4d540b
commit c7bc8e97d5
4 changed files with 93 additions and 27 deletions

View File

@@ -24,6 +24,7 @@ import 'package:photos/ui/components/models/button_type.dart';
import "package:photos/ui/components/text_input_widget.dart";
import 'package:photos/ui/sharing/user_avator_widget.dart';
import "package:photos/utils/dialog_util.dart";
import "package:photos/utils/person_contact_linking_util.dart";
import "package:photos/utils/share_util.dart";
class LinkEmailScreen extends StatefulWidget {
@@ -214,17 +215,21 @@ class _LinkEmailScreen extends State<LinkEmailScreen> {
}
});
} else {
final result = await linkEmailToPerson(
newEmail,
widget.personID!,
context,
);
if (!result) {
_textController.clear();
return;
}
try {
final result = await linkEmailToPerson(
newEmail,
widget.personID!,
context,
);
if (!result) {
_textController.clear();
return;
}
Navigator.of(context).pop(newEmail);
Navigator.of(context).pop(newEmail);
} catch (e) {
_logger.severe("Failed to link email to person", e);
}
}
},
),
@@ -325,6 +330,10 @@ class _LinkEmailScreen extends State<LinkEmailScreen> {
String personID,
BuildContext context,
) async {
if (await checkIfEmailAlreadyAssignedToAPerson(context, email)) {
throw Exception("Email already linked to a person");
}
String? publicKey;
try {

View File

@@ -17,6 +17,7 @@ import "package:photos/ui/components/dialog_widget.dart";
import "package:photos/ui/components/models/button_type.dart";
import "package:photos/ui/viewer/search/result/person_face_widget.dart";
import "package:photos/utils/dialog_util.dart";
import "package:photos/utils/person_contact_linking_util.dart";
import "package:photos/utils/toast_util.dart";
class PersonEntityWithThumbnailFile {
@@ -45,6 +46,7 @@ class _LinkContactToPersonSelectionPageState
extends State<LinkContactToPersonSelectionPage> {
late Future<List<PersonEntityWithThumbnailFile>>
_personEntitiesWithThumnailFile;
final _logger = Logger('LinkContactToPersonSelectionPage');
@override
void initState() {
@@ -115,15 +117,21 @@ class _LinkContactToPersonSelectionPageState
itemBuilder: (context, index) {
return _RoundedPersonFaceWidget(
onTap: () async {
await linkPersonToContact(
context,
emailToLink: widget.emailToLink!,
personEntity: results[index].person,
).then((updatedPerson) {
if (updatedPerson != null) {
Navigator.of(context).pop(updatedPerson);
}
});
try {
unawaited(
linkPersonToContact(
context,
emailToLink: widget.emailToLink!,
personEntity: results[index].person,
).then((updatedPerson) {
if (updatedPerson != null) {
Navigator.of(context).pop(updatedPerson);
}
}),
);
} catch (e) {
_logger.severe("Failed to link person to contact", e);
}
},
itemSize: itemSize,
personEntitiesWithThumbnailFile: results[index],
@@ -141,6 +149,10 @@ class _LinkContactToPersonSelectionPageState
required String emailToLink,
required PersonEntity personEntity,
}) async {
if (await checkIfEmailAlreadyAssignedToAPerson(context, emailToLink)) {
throw Exception("Email already linked");
}
final personName = personEntity.data.name;
PersonEntity? updatedPerson;
final result = await showDialogWidget(

View File

@@ -31,6 +31,7 @@ import "package:photos/ui/viewer/people/person_row_item.dart";
import "package:photos/ui/viewer/search/result/person_face_widget.dart";
import "package:photos/utils/dialog_util.dart";
import "package:photos/utils/navigation_util.dart";
import "package:photos/utils/person_contact_linking_util.dart";
import "package:photos/utils/toast_util.dart";
class SaveOrEditPerson extends StatefulWidget {
@@ -379,15 +380,23 @@ class _SaveOrEditPersonState extends State<SaveOrEditPerson> {
shouldStickToDarkTheme: true,
onTap: () async {
if (widget.isEditing) {
updatedPersonEntity = await updatePerson(context);
try {
updatedPersonEntity = await updatePerson(context);
} catch (e) {
_logger.severe("Error updating person", e);
}
} else {
updatedPersonEntity = await addNewPerson(
context,
text: _inputName,
clusterID: widget.clusterID!,
birthdate: _selectedDate,
email: _email,
);
try {
updatedPersonEntity = await addNewPerson(
context,
text: _inputName,
clusterID: widget.clusterID!,
birthdate: _selectedDate,
email: _email,
);
} catch (e) {
_logger.severe("Error updating person", e);
}
}
},
),
@@ -530,6 +539,11 @@ class _SaveOrEditPersonState extends State<SaveOrEditPerson> {
String? birthdate,
String? email,
}) async {
if (email != null &&
email.isNotEmpty &&
await checkIfEmailAlreadyAssignedToAPerson(context, email)) {
throw Exception("Email already assigned to a person");
}
try {
if (userAlreadyAssigned) {
return null;
@@ -576,6 +590,12 @@ class _SaveOrEditPersonState extends State<SaveOrEditPerson> {
Future<PersonEntity?> updatePerson(BuildContext context) async {
try {
if (_email != null &&
_email!.isNotEmpty &&
_email != person!.data.email &&
await checkIfEmailAlreadyAssignedToAPerson(context, _email!)) {
throw Exception("Email already assigned to a person");
}
final String name = _inputName.trim();
final String? birthDate = _selectedDate;
final personEntity = await PersonService.instance.updateAttributes(

View File

@@ -0,0 +1,25 @@
import "dart:io";
import "package:flutter/material.dart";
import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
import "package:photos/utils/dialog_util.dart";
Future<bool> checkIfEmailAlreadyAssignedToAPerson(
BuildContext context,
String email,
) async {
final persons = await PersonService.instance.getPersons();
for (var person in persons) {
if (person.data.email == email) {
await showErrorDialog(
context,
"Email already linked",
"This email is already linked to a person",
useRootNavigator: Platform.isIOS,
);
return true;
}
}
return false;
}