mirror of
https://github.com/bitwarden/mobile
synced 2025-12-10 05:13:31 +00:00
wip
This commit is contained in:
@@ -9,5 +9,6 @@ namespace Bit.App.Abstractions
|
|||||||
{
|
{
|
||||||
Task<IEnumerable<Site>> GetAllAsync();
|
Task<IEnumerable<Site>> GetAllAsync();
|
||||||
Task<ApiResult<SiteResponse>> SaveAsync(Site site);
|
Task<ApiResult<SiteResponse>> SaveAsync(Site site);
|
||||||
|
Task<ApiResult<object>> DeleteAsync(string id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
<Compile Include="Abstractions\Services\ISecureStorageService.cs" />
|
<Compile Include="Abstractions\Services\ISecureStorageService.cs" />
|
||||||
<Compile Include="Abstractions\Services\ISqlService.cs" />
|
<Compile Include="Abstractions\Services\ISqlService.cs" />
|
||||||
<Compile Include="Behaviors\EmailValidationBehavior.cs" />
|
<Compile Include="Behaviors\EmailValidationBehavior.cs" />
|
||||||
|
<Compile Include="Behaviors\ConnectivityBehavior.cs" />
|
||||||
<Compile Include="Behaviors\RequiredValidationBehavior.cs" />
|
<Compile Include="Behaviors\RequiredValidationBehavior.cs" />
|
||||||
<Compile Include="Models\Api\ApiError.cs" />
|
<Compile Include="Models\Api\ApiError.cs" />
|
||||||
<Compile Include="Models\Api\ApiResult.cs" />
|
<Compile Include="Models\Api\ApiResult.cs" />
|
||||||
@@ -84,6 +85,7 @@
|
|||||||
<Compile Include="Pages\VaultListPage.cs" />
|
<Compile Include="Pages\VaultListPage.cs" />
|
||||||
<Compile Include="Services\ApiService.cs" />
|
<Compile Include="Services\ApiService.cs" />
|
||||||
<Compile Include="Utilities\Extentions.cs" />
|
<Compile Include="Utilities\Extentions.cs" />
|
||||||
|
<Compile Include="Utilities\TokenHttpRequestMessage.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
|||||||
43
src/App/Behaviors/ConnectivityBehavior.cs
Normal file
43
src/App/Behaviors/ConnectivityBehavior.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App.Behaviors
|
||||||
|
{
|
||||||
|
public class ConnectivityBehavior : Behavior<Element>
|
||||||
|
{
|
||||||
|
private readonly IConnectivity _connectivity;
|
||||||
|
|
||||||
|
public ConnectivityBehavior()
|
||||||
|
{
|
||||||
|
_connectivity = Resolver.Resolve<IConnectivity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("Connected", typeof(bool), typeof(ConnectivityBehavior), false);
|
||||||
|
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
|
||||||
|
|
||||||
|
public bool Connected
|
||||||
|
{
|
||||||
|
get { return (bool)GetValue(IsValidProperty); }
|
||||||
|
private set { SetValue(IsValidPropertyKey, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAttachedTo(Element el)
|
||||||
|
{
|
||||||
|
_connectivity.ConnectivityChanged += ConnectivityChanged;
|
||||||
|
base.OnAttachedTo(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
|
||||||
|
{
|
||||||
|
Connected = e.IsConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDetachingFrom(Element el)
|
||||||
|
{
|
||||||
|
_connectivity.ConnectivityChanged -= ConnectivityChanged;
|
||||||
|
base.OnDetachingFrom(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,9 +18,10 @@ namespace Bit.App.Behaviors
|
|||||||
private set { SetValue(IsValidPropertyKey, value); }
|
private set { SetValue(IsValidPropertyKey, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAttachedTo(Entry bindable)
|
protected override void OnAttachedTo(Entry entry)
|
||||||
{
|
{
|
||||||
bindable.TextChanged += HandleTextChanged;
|
entry.TextChanged += HandleTextChanged;
|
||||||
|
base.OnAttachedTo(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleTextChanged(object sender, TextChangedEventArgs e)
|
void HandleTextChanged(object sender, TextChangedEventArgs e)
|
||||||
@@ -29,9 +30,10 @@ namespace Bit.App.Behaviors
|
|||||||
((Entry)sender).BackgroundColor = IsValid ? Color.Default : Color.Red;
|
((Entry)sender).BackgroundColor = IsValid ? Color.Default : Color.Red;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDetachingFrom(Entry bindable)
|
protected override void OnDetachingFrom(Entry entry)
|
||||||
{
|
{
|
||||||
bindable.TextChanged -= HandleTextChanged;
|
entry.TextChanged -= HandleTextChanged;
|
||||||
|
base.OnDetachingFrom(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ namespace Bit.App.Behaviors
|
|||||||
private set { SetValue(IsValidPropertyKey, value); }
|
private set { SetValue(IsValidPropertyKey, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAttachedTo(Entry bindable)
|
protected override void OnAttachedTo(Entry entry)
|
||||||
{
|
{
|
||||||
bindable.TextChanged += HandleTextChanged;
|
entry.TextChanged += HandleTextChanged;
|
||||||
|
base.OnAttachedTo(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleTextChanged(object sender, TextChangedEventArgs e)
|
void HandleTextChanged(object sender, TextChangedEventArgs e)
|
||||||
@@ -25,9 +26,10 @@ namespace Bit.App.Behaviors
|
|||||||
((Entry)sender).BackgroundColor = IsValid ? Color.Default : Color.Red;
|
((Entry)sender).BackgroundColor = IsValid ? Color.Default : Color.Red;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDetachingFrom(Entry bindable)
|
protected override void OnDetachingFrom(Entry entry)
|
||||||
{
|
{
|
||||||
bindable.TextChanged -= HandleTextChanged;
|
entry.TextChanged -= HandleTextChanged;
|
||||||
|
base.OnDetachingFrom(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
|
||||||
@@ -10,6 +6,8 @@ namespace Bit.App.Models
|
|||||||
{
|
{
|
||||||
public class CipherString
|
public class CipherString
|
||||||
{
|
{
|
||||||
|
private string _decryptedValue;
|
||||||
|
|
||||||
public CipherString(string encryptedString)
|
public CipherString(string encryptedString)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrWhiteSpace(encryptedString) || !encryptedString.Contains("|"))
|
if(string.IsNullOrWhiteSpace(encryptedString) || !encryptedString.Contains("|"))
|
||||||
@@ -43,8 +41,13 @@ namespace Bit.App.Models
|
|||||||
|
|
||||||
public string Decrypt()
|
public string Decrypt()
|
||||||
{
|
{
|
||||||
var cryptoService = Resolver.Resolve<ICryptoService>();
|
if(_decryptedValue == null)
|
||||||
return cryptoService.Decrypt(this);
|
{
|
||||||
|
var cryptoService = Resolver.Resolve<ICryptoService>();
|
||||||
|
_decryptedValue = cryptoService.Decrypt(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _decryptedValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace Bit.App.Models.Data
|
|||||||
|
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
[Indexed]
|
||||||
public string UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace Bit.App.Models.Data
|
|||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string FolderId { get; set; }
|
public string FolderId { get; set; }
|
||||||
|
[Indexed]
|
||||||
public string UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
|
|||||||
@@ -8,40 +8,39 @@ namespace Bit.App.Models.View
|
|||||||
{
|
{
|
||||||
public class Site
|
public class Site
|
||||||
{
|
{
|
||||||
public Site(Models.Site site)
|
public Site(Models.Site site, string folderId)
|
||||||
{
|
{
|
||||||
Id = site.Id;
|
Id = site.Id;
|
||||||
|
FolderId = folderId;
|
||||||
Name = site.Name?.Decrypt();
|
Name = site.Name?.Decrypt();
|
||||||
Username = site.Username?.Decrypt();
|
Username = site.Username?.Decrypt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
public string FolderId { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Folder : ObservableCollection<Site>
|
public class Folder : ObservableCollection<Site>
|
||||||
{
|
{
|
||||||
public Folder(string name) { Name = name; }
|
public Folder(IEnumerable<Models.Site> sites, string folderId = null)
|
||||||
|
|
||||||
public Folder(IEnumerable<Models.Site> sites)
|
|
||||||
{
|
{
|
||||||
Name = "(none)";
|
|
||||||
foreach(var site in sites)
|
foreach(var site in sites)
|
||||||
{
|
{
|
||||||
Items.Add(new Site(site));
|
Items.Add(new Site(site, folderId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Folder(Models.Folder folder, IEnumerable<Models.Site> sites)
|
public Folder(Models.Folder folder, IEnumerable<Models.Site> sites)
|
||||||
: this(sites)
|
: this(sites, folder.Id)
|
||||||
{
|
{
|
||||||
Id = folder.Id;
|
Id = folder.Id;
|
||||||
Name = folder.Name?.Decrypt();
|
Name = folder.Name?.Decrypt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; } = "(none)";
|
||||||
public string FirstLetter { get { return Name.Substring(0, 1); } }
|
public string FirstLetter { get { return Name.Substring(0, 1); } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Bit.App.Pages
|
|||||||
var folderService = Resolver.Resolve<IFolderService>();
|
var folderService = Resolver.Resolve<IFolderService>();
|
||||||
var userDialogs = Resolver.Resolve<IUserDialogs>();
|
var userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
|
|
||||||
var folders = folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name);
|
var folders = folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt());
|
||||||
|
|
||||||
var uriEntry = new Entry { Keyboard = Keyboard.Url };
|
var uriEntry = new Entry { Keyboard = Keyboard.Url };
|
||||||
var nameEntry = new Entry();
|
var nameEntry = new Entry();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Acr.UserDialogs;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.View;
|
using Bit.App.Models.View;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
@@ -13,67 +14,143 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
private readonly IFolderService _folderService;
|
private readonly IFolderService _folderService;
|
||||||
private readonly ISiteService _siteService;
|
private readonly ISiteService _siteService;
|
||||||
private ListView _listView = new ListView();
|
private readonly IUserDialogs _userDialogs;
|
||||||
|
|
||||||
public VaultListPage()
|
public VaultListPage()
|
||||||
{
|
{
|
||||||
_folderService = Resolver.Resolve<IFolderService>();
|
_folderService = Resolver.Resolve<IFolderService>();
|
||||||
_siteService = Resolver.Resolve<ISiteService>();
|
_siteService = Resolver.Resolve<ISiteService>();
|
||||||
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
|
|
||||||
var addSiteToolBarItem = new ToolbarItem("+", null, async () =>
|
Init();
|
||||||
{
|
}
|
||||||
var selection = await DisplayActionSheet("Add", "Cancel", null, "Add New Folder", "Add New Site");
|
|
||||||
if(selection == "Add New Folder")
|
|
||||||
{
|
|
||||||
var addFolderPage = new VaultAddFolderPage();
|
|
||||||
await Navigation.PushAsync(addFolderPage);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var addSitePage = new VaultAddSitePage();
|
|
||||||
await Navigation.PushAsync(addSitePage);
|
|
||||||
|
|
||||||
}
|
public ObservableCollection<VaultView.Folder> Folders { get; private set; } = new ObservableCollection<VaultView.Folder>();
|
||||||
}, ToolbarItemOrder.Default, 0);
|
|
||||||
|
|
||||||
ToolbarItems.Add(addSiteToolBarItem);
|
private void Init()
|
||||||
|
{
|
||||||
|
ToolbarItems.Add(new AddSiteToolBarItem(this));
|
||||||
|
|
||||||
_listView.IsGroupingEnabled = true;
|
var moreAction = new MenuItem { Text = "More" };
|
||||||
_listView.GroupDisplayBinding = new Binding("Name");
|
moreAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
|
||||||
_listView.ItemSelected += FolderSelected;
|
moreAction.Clicked += MoreClickedAsync;
|
||||||
_listView.ItemTemplate = new DataTemplate(() =>
|
|
||||||
{
|
var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true };
|
||||||
var cell = new TextCell();
|
deleteAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
|
||||||
cell.SetBinding<VaultView.Site>(TextCell.TextProperty, s => s.Name);
|
deleteAction.Clicked += DeleteClickedAsync;
|
||||||
cell.SetBinding<VaultView.Site>(TextCell.DetailProperty, s => s.Username);
|
|
||||||
return cell;
|
var listView = new ListView { IsGroupingEnabled = true, ItemsSource = Folders };
|
||||||
});
|
listView.GroupDisplayBinding = new Binding("Name");
|
||||||
|
listView.ItemSelected += SiteSelected;
|
||||||
|
listView.ItemTemplate = new DataTemplate(() => new VaultListViewCell(moreAction, deleteAction));
|
||||||
|
|
||||||
Title = "My Vault";
|
Title = "My Vault";
|
||||||
Content = _listView;
|
Content = listView;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAppearing()
|
protected override void OnAppearing()
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
|
LoadFoldersAsync().Wait();
|
||||||
|
}
|
||||||
|
|
||||||
var folders = _folderService.GetAllAsync().GetAwaiter().GetResult();
|
private async Task LoadFoldersAsync()
|
||||||
var sites = _siteService.GetAllAsync().GetAwaiter().GetResult();
|
{
|
||||||
|
Folders.Clear();
|
||||||
|
|
||||||
|
var folders = await _folderService.GetAllAsync();
|
||||||
|
var sites = await _siteService.GetAllAsync();
|
||||||
|
|
||||||
|
foreach(var folder in folders)
|
||||||
|
{
|
||||||
|
var f = new VaultView.Folder(folder, sites.Where(s => s.FolderId == folder.Id));
|
||||||
|
Folders.Add(f);
|
||||||
|
}
|
||||||
|
|
||||||
var folderItems = folders.Select(f => new VaultView.Folder(f, sites.Where(s => s.FolderId == f.Id))).ToList();
|
|
||||||
// add the sites with no folder
|
// add the sites with no folder
|
||||||
folderItems.Add(new VaultView.Folder(sites.Where(s => s.FolderId != null)));
|
var noneFolder = new VaultView.Folder(sites.Where(s => s.FolderId == null));
|
||||||
_listView.ItemsSource = folderItems;
|
Folders.Add(noneFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderSelected(object sender, SelectedItemChangedEventArgs e)
|
private void SiteSelected(object sender, SelectedItemChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SiteSelected(object sender, SelectedItemChangedEventArgs e)
|
private async void MoreClickedAsync(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
var mi = sender as MenuItem;
|
||||||
|
var site = mi.CommandParameter as VaultView.Site;
|
||||||
|
var selection = await DisplayActionSheet("More Options", "Cancel", null, "View", "Edit", "Copy Password", "Copy Username", "Go To Website");
|
||||||
|
|
||||||
|
switch(selection)
|
||||||
|
{
|
||||||
|
case "View":
|
||||||
|
case "Edit":
|
||||||
|
case "Copy Password":
|
||||||
|
case "Copy Username":
|
||||||
|
case "Go To Website":
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void DeleteClickedAsync(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var mi = sender as MenuItem;
|
||||||
|
var site = mi.CommandParameter as VaultView.Site;
|
||||||
|
var deleteCall = await _siteService.DeleteAsync(site.Id);
|
||||||
|
|
||||||
|
if(deleteCall.Succeeded)
|
||||||
|
{
|
||||||
|
var folder = Folders.Single(f => f.Id == site.FolderId);
|
||||||
|
var siteIndex = folder.Select((s, i) => new { s, i }).First(s => s.s.Id == site.Id).i;
|
||||||
|
folder.RemoveAt(siteIndex);
|
||||||
|
_userDialogs.SuccessToast("Site deleted.");
|
||||||
|
}
|
||||||
|
else if(deleteCall.Errors.Count() > 0)
|
||||||
|
{
|
||||||
|
await DisplayAlert("An error has occurred", deleteCall.Errors.First().Message, "Ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AddSiteToolBarItem : ToolbarItem
|
||||||
|
{
|
||||||
|
private readonly VaultListPage _page;
|
||||||
|
|
||||||
|
public AddSiteToolBarItem(VaultListPage page)
|
||||||
|
{
|
||||||
|
_page = page;
|
||||||
|
Text = "Add";
|
||||||
|
Icon = "";
|
||||||
|
Clicked += ClickedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ClickedItem(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var selection = await _page.DisplayActionSheet("Add", "Cancel", null, "Add New Folder", "Add New Site");
|
||||||
|
if(selection == "Add New Folder")
|
||||||
|
{
|
||||||
|
var addFolderPage = new VaultAddFolderPage();
|
||||||
|
await _page.Navigation.PushAsync(addFolderPage);
|
||||||
|
}
|
||||||
|
else if(selection == "Add New Site")
|
||||||
|
{
|
||||||
|
var addSitePage = new VaultAddSitePage();
|
||||||
|
await _page.Navigation.PushAsync(addSitePage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class VaultListViewCell : TextCell
|
||||||
|
{
|
||||||
|
public VaultListViewCell(MenuItem moreMenuItem, MenuItem deleteMenuItem)
|
||||||
|
{
|
||||||
|
this.SetBinding<VaultView.Site>(TextProperty, s => s.Name);
|
||||||
|
this.SetBinding<VaultView.Site>(DetailProperty, s => s.Username);
|
||||||
|
ContextActions.Add(moreMenuItem);
|
||||||
|
ContextActions.Add(deleteMenuItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Bit.App.Models.Data;
|
|||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Bit.App.Services
|
namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
@@ -30,26 +29,25 @@ namespace Bit.App.Services
|
|||||||
public new Task<Folder> GetByIdAsync(string id)
|
public new Task<Folder> GetByIdAsync(string id)
|
||||||
{
|
{
|
||||||
var data = Connection.Table<FolderData>().Where(f => f.UserId == _authService.UserId && f.Id == id).FirstOrDefault();
|
var data = Connection.Table<FolderData>().Where(f => f.UserId == _authService.UserId && f.Id == id).FirstOrDefault();
|
||||||
return Task.FromResult(new Folder(data));
|
var folder = new Folder(data);
|
||||||
|
return Task.FromResult(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public new Task<IEnumerable<Folder>> GetAllAsync()
|
public new Task<IEnumerable<Folder>> GetAllAsync()
|
||||||
{
|
{
|
||||||
var data = Connection.Table<FolderData>().Where(f => f.UserId == _authService.UserId).Cast<FolderData>();
|
var data = Connection.Table<FolderData>().Where(f => f.UserId == _authService.UserId).Cast<FolderData>();
|
||||||
return Task.FromResult(data.Select(f => new Folder(f)));
|
var folders = data.Select(f => new Folder(f));
|
||||||
|
return Task.FromResult(folders);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResult<FolderResponse>> SaveAsync(Folder folder)
|
public async Task<ApiResult<FolderResponse>> SaveAsync(Folder folder)
|
||||||
{
|
{
|
||||||
var request = new FolderRequest(folder);
|
var request = new FolderRequest(folder);
|
||||||
var requestContent = JsonConvert.SerializeObject(request);
|
var requestMessage = new TokenHttpRequestMessage(request)
|
||||||
var requestMessage = new HttpRequestMessage
|
|
||||||
{
|
{
|
||||||
Method = folder.Id == null ? HttpMethod.Post : HttpMethod.Put,
|
Method = folder.Id == null ? HttpMethod.Post : HttpMethod.Put,
|
||||||
RequestUri = new Uri(_apiService.Client.BaseAddress, folder.Id == null ? "/folders" : string.Concat("/folders/", folder.Id)),
|
RequestUri = new Uri(_apiService.Client.BaseAddress, folder.Id == null ? "/folders" : $"/folders/{folder.Id}"),
|
||||||
Content = new StringContent(requestContent, Encoding.UTF8, "application/json")
|
|
||||||
};
|
};
|
||||||
requestMessage.Headers.Add("Authorization", string.Concat("Bearer ", _authService.Token));
|
|
||||||
|
|
||||||
var response = await _apiService.Client.SendAsync(requestMessage);
|
var response = await _apiService.Client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
|
|||||||
@@ -40,9 +40,14 @@ namespace Bit.App.Services
|
|||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task DeleteAsync(T obj)
|
protected virtual async Task DeleteAsync(T obj)
|
||||||
{
|
{
|
||||||
Connection.Delete<T>(obj.Id);
|
await DeleteAsync(obj.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Task DeleteAsync(TId id)
|
||||||
|
{
|
||||||
|
Connection.Delete<T>(id);
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
@@ -30,20 +29,18 @@ namespace Bit.App.Services
|
|||||||
public new Task<IEnumerable<Site>> GetAllAsync()
|
public new Task<IEnumerable<Site>> GetAllAsync()
|
||||||
{
|
{
|
||||||
var data = Connection.Table<SiteData>().Where(f => f.UserId == _authService.UserId).Cast<SiteData>();
|
var data = Connection.Table<SiteData>().Where(f => f.UserId == _authService.UserId).Cast<SiteData>();
|
||||||
return Task.FromResult(data.Select(s => new Site(s)));
|
var sites = data.Select(s => new Site(s));
|
||||||
|
return Task.FromResult(sites);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResult<SiteResponse>> SaveAsync(Site site)
|
public async Task<ApiResult<SiteResponse>> SaveAsync(Site site)
|
||||||
{
|
{
|
||||||
var request = new SiteRequest(site);
|
var request = new SiteRequest(site);
|
||||||
var requestContent = JsonConvert.SerializeObject(request);
|
var requestMessage = new TokenHttpRequestMessage(request)
|
||||||
var requestMessage = new HttpRequestMessage
|
|
||||||
{
|
{
|
||||||
Method = site.Id == null ? HttpMethod.Post : HttpMethod.Put,
|
Method = site.Id == null ? HttpMethod.Post : HttpMethod.Put,
|
||||||
RequestUri = new Uri(_apiService.Client.BaseAddress, site.Id == null ? "/sites" : string.Concat("/folders/", site.Id)),
|
RequestUri = new Uri(_apiService.Client.BaseAddress, site.Id == null ? "/sites" : $"/folders/{site.Id}")
|
||||||
Content = new StringContent(requestContent, Encoding.UTF8, "application/json")
|
|
||||||
};
|
};
|
||||||
requestMessage.Headers.Add("Authorization", string.Concat("Bearer ", _authService.Token));
|
|
||||||
|
|
||||||
var response = await _apiService.Client.SendAsync(requestMessage);
|
var response = await _apiService.Client.SendAsync(requestMessage);
|
||||||
if(!response.IsSuccessStatusCode)
|
if(!response.IsSuccessStatusCode)
|
||||||
@@ -57,15 +54,33 @@ namespace Bit.App.Services
|
|||||||
|
|
||||||
if(site.Id == null)
|
if(site.Id == null)
|
||||||
{
|
{
|
||||||
await CreateAsync(data);
|
await base.CreateAsync(data);
|
||||||
site.Id = responseObj.Id;
|
site.Id = responseObj.Id;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await ReplaceAsync(data);
|
await base.ReplaceAsync(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ApiResult<SiteResponse>.Success(responseObj, response.StatusCode);
|
return ApiResult<SiteResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public new async Task<ApiResult<object>> DeleteAsync(string id)
|
||||||
|
{
|
||||||
|
var requestMessage = new TokenHttpRequestMessage
|
||||||
|
{
|
||||||
|
Method = HttpMethod.Delete,
|
||||||
|
RequestUri = new Uri(_apiService.Client.BaseAddress, $"/sites/{id}")
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await _apiService.Client.SendAsync(requestMessage);
|
||||||
|
if(!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
return await _apiService.HandleErrorAsync<object>(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.DeleteAsync(id);
|
||||||
|
return ApiResult<object>.Success(null, response.StatusCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/App/Utilities/TokenHttpRequestMessage.cs
Normal file
24
src/App/Utilities/TokenHttpRequestMessage.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App
|
||||||
|
{
|
||||||
|
public class TokenHttpRequestMessage : HttpRequestMessage
|
||||||
|
{
|
||||||
|
public TokenHttpRequestMessage()
|
||||||
|
{
|
||||||
|
var authService = Resolver.Resolve<IAuthService>();
|
||||||
|
Headers.Add("Authorization", $"Bearer {authService.Token}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenHttpRequestMessage(object requestObject)
|
||||||
|
: this()
|
||||||
|
{
|
||||||
|
var stringContent = JsonConvert.SerializeObject(requestObject);
|
||||||
|
Content = new StringContent(stringContent, Encoding.UTF8, "application/json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user