Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
PetitionIdentityViewModel.cs
1using CommunityToolkit.Mvvm.ComponentModel;
2using CommunityToolkit.Mvvm.Input;
8using System.Collections.ObjectModel;
12
14{
19 {
20 private readonly PhotosLoader photosLoader;
21 private readonly string? requestorFullJid;
22 private readonly string? requestedIdentityId;
23 private readonly string? petitionId;
24 private readonly string? bareJid;
25
30 public PetitionIdentityViewModel(PetitionIdentityNavigationArgs? Args)
31 {
32 this.photosLoader = new PhotosLoader(this.Photos);
33
34 if (Args is not null)
35 {
36 this.RequestorIdentity = Args.RequestorIdentity;
37 this.requestorFullJid = Args.RequestorFullJid;
38 this.requestedIdentityId = Args.RequestedIdentityId;
39 this.petitionId = Args.PetitionId;
40 this.Purpose = Args.Purpose;
41
42 if (!string.IsNullOrEmpty(this.requestorFullJid))
43 this.bareJid = XmppClient.GetBareJID(this.requestorFullJid);
44 else if (Args.RequestorIdentity is not null)
45 this.bareJid = Args.RequestorIdentity.GetJid();
46 else
47 this.bareJid = string.Empty;
48 }
49 }
50
52 protected override async Task OnInitialize()
53 {
54 await base.OnInitialize();
55
56 if (!string.IsNullOrEmpty(this.bareJid))
57 {
58 ContactInfo Info = await ContactInfo.FindByBareJid(this.bareJid);
59
60 if (this.RequestorIdentity is not null &&
61 Info is not null &&
62 (Info.LegalIdentity is null || (
63 Info.LegalId != this.RequestorIdentity?.Id &&
64 Info.LegalIdentity is not null &&
65 Info.LegalIdentity.Created < this.RequestorIdentity!.Created &&
66 this.RequestorIdentity.State == IdentityState.Approved)))
67 {
68 Info.LegalId = this.LegalId;
69 Info.LegalIdentity = this.RequestorIdentity;
70 Info.FriendlyName = ContactInfo.GetFriendlyName(this.RequestorIdentity);
71
72 await Database.Update(Info);
73 await Database.Provider.Flush();
74 }
75
76 this.ThirdPartyInContacts = Info is not null;
77 }
78
79 this.AssignProperties();
80 EvaluateAllCommands();
81
82 this.ReloadPhotos();
83 }
84
85 private async void ReloadPhotos()
86 {
87 try
88 {
89 this.photosLoader.CancelLoadPhotos();
90
91 Attachment[]? Attachments = this.RequestorIdentity?.Attachments;
92
93 if (Attachments is not null)
94 {
95 Photo? First = await this.photosLoader.LoadPhotos(Attachments, SignWith.LatestApprovedId);
96
97 this.FirstPhotoSource = First?.Source;
98 this.FirstPhotoRotation = First?.Rotation ?? 0;
99 }
100 }
101 catch (Exception ex)
102 {
103 ServiceRef.LogService.LogException(ex);
104 }
105 }
106
108 protected override async Task OnDispose()
109 {
110 this.photosLoader.CancelLoadPhotos();
111
112 await base.OnDispose();
113 }
114
115 private static void EvaluateAllCommands()
116 {
117 }
118
122 public ObservableCollection<Photo> Photos { get; } = [];
123
127 public LegalIdentity? RequestorIdentity { get; private set; }
128
129 [RelayCommand]
130 private async Task Accept()
131 {
132 if (!await App.AuthenticateUser(AuthenticationPurpose.PetitionIdentity))
133 return;
134
135 bool Succeeded = await ServiceRef.NetworkService.TryRequest(() =>
136 {
137 return ServiceRef.XmppService.SendPetitionIdentityResponse(this.requestedIdentityId, this.petitionId!,
138 this.requestorFullJid!, true);
139 });
140
141 if (Succeeded)
142 await ServiceRef.UiService.GoBackAsync();
143 }
144
145 [RelayCommand]
146 private async Task Decline()
147 {
148 bool Succeeded = await ServiceRef.NetworkService.TryRequest(() =>
149 {
150 return ServiceRef.XmppService.SendPetitionIdentityResponse(this.requestedIdentityId, this.petitionId!,
151 this.requestorFullJid!, false);
152 });
153
154 if (Succeeded)
155 await this.GoBack();
156 }
157
158 [RelayCommand]
159 private async Task Ignore()
160 {
161 await this.GoBack();
162 }
163
164 // Full name of requesting entity.
165 public string FullName => ContactInfo.GetFullName(this.FirstName, this.MiddleNames, this.LastNames);
166
167 #region Properties
168
172 [ObservableProperty]
173 private DateTime created;
174
178 [ObservableProperty]
179 private DateTime? updated;
180
184 [ObservableProperty]
185 private DateTime? expires;
186
190 [ObservableProperty]
191 private string? legalId;
192
196 [ObservableProperty]
197 private string? networkId;
198
202 [ObservableProperty]
203 private IdentityState state;
204
208 [ObservableProperty]
209 private DateTime? from;
210
214 [ObservableProperty]
215 private DateTime? to;
216
220 [ObservableProperty]
221 [NotifyPropertyChangedFor(nameof(FullName))]
222 private string? firstName;
223
227 [ObservableProperty]
228 [NotifyPropertyChangedFor(nameof(FullName))]
229 private string? middleNames;
230
234 [ObservableProperty]
235 [NotifyPropertyChangedFor(nameof(FullName))]
236 private string? lastNames;
237
241 [ObservableProperty]
242 private string? personalNumber;
243
247 [ObservableProperty]
248 private string? address;
249
253 [ObservableProperty]
254 private string? address2;
255
259 [ObservableProperty]
260 private string? zipCode;
261
265 [ObservableProperty]
266 private string? area;
267
271 [ObservableProperty]
272 private string? city;
273
277 [ObservableProperty]
278 private string? region;
279
283 [ObservableProperty]
284 private string? countryCode;
285
289 [ObservableProperty]
290 private string? nationalityCode;
291
295 [ObservableProperty]
296 private string? gender;
297
301 [ObservableProperty]
302 private DateTime? birthDate;
303
307 [ObservableProperty]
308 private string? orgName;
309
313 [ObservableProperty]
314 private string? orgNumber;
315
319 [ObservableProperty]
320 private string? orgDepartment;
321
325 [ObservableProperty]
326 private string? orgRole;
327
331 [ObservableProperty]
332 private string? orgAddress;
333
337 [ObservableProperty]
338 private string? orgAddress2;
339
343 [ObservableProperty]
344 private string? orgZipCode;
345
349 [ObservableProperty]
350 private string? orgArea;
351
355 [ObservableProperty]
356 private string? orgCity;
357
361 [ObservableProperty]
362 private string? orgRegion;
363
367 [ObservableProperty]
368 private string? orgCountryCode;
369
373 [ObservableProperty]
374 private bool hasOrg;
375
379 [ObservableProperty]
380 private bool hasPhotos;
381
385 [ObservableProperty]
386 private string? phoneNr;
387
391 [ObservableProperty]
392 private string? eMail;
393
397 [ObservableProperty]
398 private string? deviceId;
399
403 [ObservableProperty]
404 private bool isApproved;
405
409 [ObservableProperty]
410 private string? purpose;
411
415 [ObservableProperty]
416 [NotifyCanExecuteChangedFor(nameof(AddContactCommand))]
417 [NotifyCanExecuteChangedFor(nameof(RemoveContactCommand))]
418 private bool thirdPartyInContacts;
419
423 [ObservableProperty]
424 private ImageSource? firstPhotoSource;
425
429 [ObservableProperty]
430 private int firstPhotoRotation;
431
432 #endregion
433
434 private void AssignProperties()
435 {
436 if (this.RequestorIdentity is not null)
437 {
438 this.Created = this.RequestorIdentity.Created;
439 this.Updated = this.RequestorIdentity.Updated.GetDateOrNullIfMinValue();
440 this.Expires = this.RequestorIdentity.To.GetDateOrNullIfMinValue();
441 this.LegalId = this.RequestorIdentity.Id;
442 this.NetworkId = this.RequestorIdentity.GetJid();
443 this.State = this.RequestorIdentity.State;
444 this.From = this.RequestorIdentity.From.GetDateOrNullIfMinValue();
445 this.To = this.RequestorIdentity.To.GetDateOrNullIfMinValue();
447 this.MiddleNames = this.RequestorIdentity[Constants.XmppProperties.MiddleNames];
449 this.PersonalNumber = this.RequestorIdentity[Constants.XmppProperties.PersonalNumber];
456 this.CountryCode = this.RequestorIdentity[Constants.XmppProperties.Country];
457 this.NationalityCode = this.RequestorIdentity[Constants.XmppProperties.Nationality];
459
460 string BirthDayStr = this.RequestorIdentity[Constants.XmppProperties.BirthDay];
461 string BirthMonthStr = this.RequestorIdentity[Constants.XmppProperties.BirthMonth];
462 string BirthYearStr = this.RequestorIdentity[Constants.XmppProperties.BirthYear];
463
464 if (!string.IsNullOrEmpty(BirthDayStr) && int.TryParse(BirthDayStr, out int BirthDay) &&
465 !string.IsNullOrEmpty(BirthMonthStr) && int.TryParse(BirthMonthStr, out int BirthMonth) &&
466 !string.IsNullOrEmpty(BirthYearStr) && int.TryParse(BirthYearStr, out int BirthYear))
467 {
468 try
469 {
470 this.BirthDate = new DateTime(BirthYear, BirthMonth, BirthDay);
471 }
472 catch (Exception ex)
473 {
474 ServiceRef.LogService.LogException(ex);
475 this.BirthDate = null;
476 }
477 }
478
481 this.OrgDepartment = this.RequestorIdentity[Constants.XmppProperties.OrgDepartment];
484 this.OrgAddress2 = this.RequestorIdentity[Constants.XmppProperties.OrgAddress2];
489 this.OrgCountryCode = this.RequestorIdentity[Constants.XmppProperties.OrgCountry];
490 this.HasOrg =
491 !string.IsNullOrEmpty(this.OrgName) ||
492 !string.IsNullOrEmpty(this.OrgNumber) ||
493 !string.IsNullOrEmpty(this.OrgDepartment) ||
494 !string.IsNullOrEmpty(this.OrgRole) ||
495 !string.IsNullOrEmpty(this.OrgAddress) ||
496 !string.IsNullOrEmpty(this.OrgAddress2) ||
497 !string.IsNullOrEmpty(this.OrgZipCode) ||
498 !string.IsNullOrEmpty(this.OrgArea) ||
499 !string.IsNullOrEmpty(this.OrgCity) ||
500 !string.IsNullOrEmpty(this.OrgRegion) ||
501 !string.IsNullOrEmpty(this.OrgCountryCode);
502 this.HasPhotos = this.Photos.Count > 0;
503 this.PhoneNr = this.RequestorIdentity[Constants.XmppProperties.Phone];
506 this.IsApproved = this.RequestorIdentity.State == IdentityState.Approved;
507 }
508 else
509 {
510 this.Created = DateTime.MinValue;
511 this.Updated = null;
512 this.LegalId = Constants.NotAvailableValue;
513 this.State = IdentityState.Compromised;
514 this.From = null;
515 this.To = null;
516 this.FirstName = Constants.NotAvailableValue;
517 this.MiddleNames = Constants.NotAvailableValue;
518 this.LastNames = Constants.NotAvailableValue;
519 this.PersonalNumber = Constants.NotAvailableValue;
520 this.Address = Constants.NotAvailableValue;
521 this.Address2 = Constants.NotAvailableValue;
522 this.ZipCode = Constants.NotAvailableValue;
523 this.Area = Constants.NotAvailableValue;
524 this.City = Constants.NotAvailableValue;
525 this.Region = Constants.NotAvailableValue;
526 this.CountryCode = Constants.NotAvailableValue;
527 this.NationalityCode = Constants.NotAvailableValue;
528 this.Gender = Constants.NotAvailableValue;
529 this.BirthDate = null;
530 this.OrgName = Constants.NotAvailableValue;
531 this.OrgNumber = Constants.NotAvailableValue;
532 this.OrgDepartment = Constants.NotAvailableValue;
533 this.OrgRole = Constants.NotAvailableValue;
534 this.OrgAddress = Constants.NotAvailableValue;
535 this.OrgAddress2 = Constants.NotAvailableValue;
536 this.OrgZipCode = Constants.NotAvailableValue;
537 this.OrgArea = Constants.NotAvailableValue;
538 this.OrgCity = Constants.NotAvailableValue;
539 this.OrgRegion = Constants.NotAvailableValue;
540 this.OrgCountryCode = Constants.NotAvailableValue;
541 this.HasOrg = false;
542 this.HasPhotos = false;
543 this.PhoneNr = Constants.NotAvailableValue;
544 this.EMail = Constants.NotAvailableValue;
545 this.DeviceId = Constants.NotAvailableValue;
546 this.IsApproved = false;
547 }
548 }
549
553 [RelayCommand]
554 private async Task Copy(object Item)
555 {
556 try
557 {
558 if (Item is string Label)
559 {
560 if (Label == this.LegalId)
561 {
562 await Clipboard.SetTextAsync(Constants.UriSchemes.IotId + ":" + this.LegalId);
563 await ServiceRef.UiService.DisplayAlert(
564 ServiceRef.Localizer[nameof(AppResources.SuccessTitle)],
565 ServiceRef.Localizer[nameof(AppResources.IdCopiedSuccessfully)]);
566 }
567 else
568 {
569 await Clipboard.SetTextAsync(Label);
570 await ServiceRef.UiService.DisplayAlert(
571 ServiceRef.Localizer[nameof(AppResources.SuccessTitle)],
572 ServiceRef.Localizer[nameof(AppResources.TagValueCopiedToClipboard)]);
573 }
574 }
575 }
576 catch (Exception ex)
577 {
578 ServiceRef.LogService.LogException(ex);
579 await ServiceRef.UiService.DisplayException(ex);
580 }
581 }
582
586 public bool CanAddContact => !this.ThirdPartyInContacts;
587
591 [RelayCommand(CanExecute = nameof(CanAddContact))]
592 private async Task AddContact()
593 {
594 if (this.RequestorIdentity is null)
595 return;
596
597 try
598 {
599 string FriendlyName = ContactInfo.GetFriendlyName(this.RequestorIdentity);
600 string BareJid = XmppClient.GetBareJID(this.requestorFullJid);
601
602 RosterItem? Item = ServiceRef.XmppService.GetRosterItem(BareJid);
603 if (Item is null)
604 ServiceRef.XmppService.AddRosterItem(new RosterItem(BareJid, FriendlyName));
605
606 ContactInfo Info = await ContactInfo.FindByBareJid(BareJid);
607 if (Info is null)
608 {
609 Info = new ContactInfo()
610 {
611 BareJid = BareJid,
612 LegalId = this.RequestorIdentity.Id,
614 FriendlyName = FriendlyName,
615 IsThing = false
616 };
617
618 await Database.Insert(Info);
619 }
620 else
621 {
622 Info.LegalId = this.requestedIdentityId;
623 Info.LegalIdentity = this.RequestorIdentity;
624 Info.FriendlyName = FriendlyName;
625
626 await Database.Update(Info);
627 }
628
629 await ServiceRef.AttachmentCacheService.MakePermanent(this.LegalId!);
630 await Database.Provider.Flush();
631
632 this.ThirdPartyInContacts = true;
633 }
634 catch (Exception ex)
635 {
636 await ServiceRef.UiService.DisplayException(ex);
637 }
638 }
639
643 public bool CanRemoveContact => this.ThirdPartyInContacts;
644
648 [RelayCommand(CanExecute = nameof(CanRemoveContact))]
649 private async Task RemoveContact()
650 {
651 try
652 {
653 if (!await ServiceRef.UiService.DisplayAlert(ServiceRef.Localizer[nameof(AppResources.Confirm)],
654 ServiceRef.Localizer[nameof(AppResources.AreYouSureYouWantToRemoveContact)],
655 ServiceRef.Localizer[nameof(AppResources.Yes)], ServiceRef.Localizer[nameof(AppResources.Cancel)]))
656 {
657 return;
658 }
659
660 string BareJid = XmppClient.GetBareJID(this.requestorFullJid);
661
662 ContactInfo Info = await ContactInfo.FindByBareJid(BareJid);
663 if (Info is not null)
664 {
665 await Database.Delete(Info);
666 await ServiceRef.AttachmentCacheService.MakeTemporary(Info.LegalId);
667 await Database.Provider.Flush();
668 }
669
670 RosterItem? Item = ServiceRef.XmppService.GetRosterItem(BareJid);
671 if (Item is not null)
672 ServiceRef.XmppService.RemoveRosterItem(BareJid);
673
674 this.ThirdPartyInContacts = false;
675 }
676 catch (Exception ex)
677 {
678 await ServiceRef.UiService.DisplayException(ex);
679 }
680 }
681 }
682}
The Application class, representing an instance of the Neuro-Access app.
Definition: App.xaml.cs:69
static Task< bool > AuthenticateUser(AuthenticationPurpose Purpose, bool Force=false)
Authenticates the user using the configured authentication method.
Definition: App.xaml.cs:981
const string IotId
The IoT ID URI Scheme (iotid)
Definition: Constants.cs:99
const string PersonalNumber
Personal number
Definition: Constants.cs:284
const string OrgAddress2
Organization Address line 2
Definition: Constants.cs:364
const string OrgArea
Organization Area
Definition: Constants.cs:369
const string OrgRegion
Organization Region
Definition: Constants.cs:384
const string Nationality
Nationality
Definition: Constants.cs:324
const string BirthYear
Birth Year
Definition: Constants.cs:344
const string OrgCity
Organization City
Definition: Constants.cs:374
const string OrgRole
Organization Role
Definition: Constants.cs:399
const string Phone
Phone number
Definition: Constants.cs:414
const string EMail
e-Mail address
Definition: Constants.cs:419
const string OrgZipCode
Organization Zip Code
Definition: Constants.cs:379
const string MiddleNames
Middle names
Definition: Constants.cs:274
const string OrgCountry
Organization Country
Definition: Constants.cs:389
const string OrgDepartment
Organization Department
Definition: Constants.cs:394
const string Address2
Address line 2
Definition: Constants.cs:294
const string OrgAddress
Organization Address line 1
Definition: Constants.cs:359
const string Address
Address line 1
Definition: Constants.cs:289
const string LastNames
Last names
Definition: Constants.cs:279
const string OrgNumber
Organization number
Definition: Constants.cs:354
const string BirthMonth
Birth Month
Definition: Constants.cs:339
const string FirstName
First name
Definition: Constants.cs:269
const string OrgName
Organization name
Definition: Constants.cs:349
A set of never changing property constants and helpful values.
Definition: Constants.cs:7
const string NotAvailableValue
A generic "no value available" string.
Definition: Constants.cs:11
Contains information about a contact.
Definition: ContactInfo.cs:21
static async Task< string > GetFriendlyName(CaseInsensitiveString RemoteId)
Gets the friendly name of a remote identity (Legal ID or Bare JID).
Definition: ContactInfo.cs:257
LegalIdentity? LegalIdentity
Legal Identity object.
Definition: ContactInfo.cs:81
static string GetFullName(LegalIdentity? Identity)
Gets the full name of a person.
Definition: ContactInfo.cs:577
static Task< ContactInfo > FindByBareJid(string BareJid)
Finds information about a contact, given its Bare JID.
Definition: ContactInfo.cs:220
CaseInsensitiveString LegalId
Legal ID of contact.
Definition: ContactInfo.cs:71
Base class that references services in the app.
Definition: ServiceRef.cs:31
static ILogService LogService
Log service.
Definition: ServiceRef.cs:91
static INetworkService NetworkService
Network service.
Definition: ServiceRef.cs:103
static IUiService UiService
Service serializing and managing UI-related tasks.
Definition: ServiceRef.cs:55
static IAttachmentCacheService AttachmentCacheService
AttachmentCache service.
Definition: ServiceRef.cs:151
static IStringLocalizer Localizer
Localization service
Definition: ServiceRef.cs:235
static IXmppService XmppService
The XMPP service for XMPP communication.
Definition: ServiceRef.cs:67
A base class for all view models, inheriting from the BindableObject. NOTE: using this class requir...
virtual async Task GoBack()
Method called when user wants to navigate to the previous screen.
The view model to bind to when displaying petitioning of an identity in a view or page.
ObservableCollection< Photo > Photos
The list of photos related to the identity being petitioned.
override async Task OnDispose()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
override async Task OnInitialize()
Method called when view is initialized for the first time. Use this method to implement registration ...
PetitionIdentityViewModel(PetitionIdentityNavigationArgs? Args)
Creates a new instance of the PetitionIdentityViewModel class.
Contains a reference to an attachment assigned to a legal object.
Definition: Attachment.cs:9
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
static string GetBareJID(string JID)
Gets the Bare JID from a JID, which may be a Full JID.
Definition: XmppClient.cs:6901
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static IDatabaseProvider Provider
Registered database provider.
Definition: Database.cs:57
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:626
static async Task Delete(object Object)
Deletes an object in the database.
Definition: Database.cs:717
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Definition: Database.cs:95
Task Flush()
Persists any pending changes.
class Photo(byte[] Binary, int Rotation)
Class containing information about a photo.
Definition: Photo.cs:8
AuthenticationPurpose
Purpose for requesting the user to authenticate itself.
IdentityState
Lists recognized legal identity states.
SignWith
Options on what keys to use when signing data.
Definition: Enumerations.cs:84