Revision 31c97141

b/trunk/Pithos.Client.WPF/Pithos.Client.WPF.csproj
262 262
    </Compile>
263 263
    <Compile Include="FileProperties\NewContainerViewModel.cs" />
264 264
    <Compile Include="PithosException.cs" />
265
    <Compile Include="Preferences\AccountViewModel.cs" />
265 266
    <Compile Include="Preferences\AddAccountView.xaml.cs">
266 267
      <DependentUpon>AddAccountView.xaml</DependentUpon>
267 268
    </Compile>
b/trunk/Pithos.Client.WPF/Preferences/AccountViewModel.cs
1
#region
2
/* -----------------------------------------------------------------------
3
 * <copyright file="AccountViewModel.cs" company="GRNet">
4
 * 
5
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or
8
 * without modification, are permitted provided that the following
9
 * conditions are met:
10
 *
11
 *   1. Redistributions of source code must retain the above
12
 *      copyright notice, this list of conditions and the following
13
 *      disclaimer.
14
 *
15
 *   2. Redistributions in binary form must reproduce the above
16
 *      copyright notice, this list of conditions and the following
17
 *      disclaimer in the documentation and/or other materials
18
 *      provided with the distribution.
19
 *
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 * The views and conclusions contained in the software and
35
 * documentation are those of the authors and should not be
36
 * interpreted as representing official policies, either expressed
37
 * or implied, of GRNET S.A.
38
 * </copyright>
39
 * -----------------------------------------------------------------------
40
 */
41
#endregion
42
using Caliburn.Micro;
43
using Pithos.Interfaces;
44

  
45
namespace Pithos.Client.WPF.Preferences
46
{
47
    /// <summary>
48
    /// ViewModel wrapper for an account
49
    /// </summary>
50
    public class AccountViewModel:PropertyChangedBase
51
    {
52

  
53
        private readonly AccountSettings _account;
54
        
55
        public AccountSettings Account
56
        {
57
            get { return _account; }
58
        }
59

  
60
        public AccountViewModel(AccountSettings account)
61
        {
62
            _account = account;            
63
        }
64

  
65

  
66
        public string AccountName
67
        {
68
            get {
69
                return _account.AccountName;
70
            }
71
            set {
72
                _account.AccountName = value;
73
                NotifyOfPropertyChange(()=>AccountName);
74
            }
75
        }
76

  
77
        public string RootPath
78
        {
79
            get { return _account.RootPath; }
80
            set 
81
            { 
82
                _account.RootPath = value;
83
                NotifyOfPropertyChange(()=>RootPath);
84
            }
85
        }
86

  
87
        public bool IsActive
88
        {
89
            get { return _account.IsActive; }
90
            set
91
            { 
92
                _account.IsActive = value;
93
                NotifyOfPropertyChange(()=>IsActive);
94
            }
95
        }
96

  
97
        public bool IsExpired
98
        {
99
            get { return _account.IsExpired; }
100
            set 
101
            { 
102
                _account.IsExpired = value;
103
                NotifyOfPropertyChange(()=>IsExpired);
104
            }
105
        }
106

  
107
        public string ServerUrl
108
        {
109
            get { return _account.ServerUrl; }
110
            set 
111
            { 
112
                _account.ServerUrl = value;
113
                NotifyOfPropertyChange(()=>ServerUrl);
114
            }
115
        }
116

  
117
        public string ApiKey
118
        {
119
            get { return _account.ApiKey; }
120
            set 
121
            {
122
                _account.ApiKey = value;
123
                NotifyOfPropertyChange(() => ApiKey);
124
            }
125
        }
126

  
127

  
128
    }
129
}
b/trunk/Pithos.Client.WPF/Preferences/PreferencesView.xaml
72 72
                            <ListBox.ItemTemplate>
73 73
                                <DataTemplate>
74 74
                                    <StackPanel Orientation="Horizontal">
75
                                    <Image Visibility="{Binding Converter={StaticResource BoolToVisible}, Path=IsExpired}" Source="/Pithos.Client.WPF;component/Images/SmallWarning.png" Margin="2,0"/>
75
                                    <Image Visibility="{Binding Converter={StaticResource BoolToVisible}, Path=IsExpired,Mode=OneWay}" Source="/Pithos.Client.WPF;component/Images/SmallWarning.png" Margin="2,0"/>
76 76
                                    <TextBlock Text="{Binding AccountName}" />
77 77
                                    </StackPanel>
78 78
                                </DataTemplate>
b/trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs
45 45

  
46 46
using System.Collections.Concurrent;
47 47
using System.ComponentModel.Composition;
48
using System.Diagnostics;
48 49
using System.IO;
49 50
using System.Net;
50 51
using System.Threading.Tasks;
......
69 70
    {
70 71
        private IEventAggregator _events;
71 72

  
73
        //Logging in the Pithos client is provided by log4net
74
        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger("Pithos");
72 75

  
73 76
        private PithosSettings _settings;
74 77
        public PithosSettings Settings
......
81 84
            }
82 85
        }
83 86

  
84
        private ObservableConcurrentCollection<AccountSettings> _accounts;
85
        public ObservableConcurrentCollection<AccountSettings> Accounts
87
        private ObservableConcurrentCollection<AccountViewModel> _accounts;
88
        public ObservableConcurrentCollection<AccountViewModel> Accounts
86 89
        {
87 90
            get { return _accounts; }
88 91
            set 
......
106 109
            Shell = shell;
107 110
            
108 111
            Settings=settings;
109
            Accounts = new ObservableConcurrentCollection<AccountSettings>();
112
            Accounts = new ObservableConcurrentCollection<AccountViewModel>();
110 113
            if (settings.Accounts == null)
111 114
            {
112 115
                settings.Accounts=new AccountsCollection();
113 116
                settings.Save();
114 117
            }
115
            Accounts.AddFromEnumerable(settings.Accounts);
118
            var accountVMs = from account in settings.Accounts
119
                             select new AccountViewModel(account);
120

  
121
            Accounts.AddFromEnumerable(accountVMs);
116 122
            
117 123
            var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
118 124
            _shortcutPath = Path.Combine(startupPath, "Pithos.lnk");
......
205 211
            var monitor = Shell.Monitors[CurrentAccount.AccountName];
206 212
            
207 213

  
208
            var model = new SelectiveSynchViewModel(monitor,_events,CurrentAccount);
214
            var model = new SelectiveSynchViewModel(monitor,_events,CurrentAccount.Account);
209 215
            if (_windowManager.ShowDialog(model) == true)
210 216
            {
211 217
                
......
213 219
        }
214 220

  
215 221
        public async Task RefreshApiKey()
216
        {            
217
            await Shell.TryAuthorize(CurrentAccount.AccountName, 3);
218
            NotifyOfPropertyChange(()=>CurrentAccount);
222
        {
223
            _events.Publish(new Notification { Title = "Authorization failed", Message = "Your API Key has probably expired. You will be directed to a page where you can renew it", Level = TraceLevel.Error });
224

  
225
            //var userName = CurrentAccount.AccountName;
226
            try
227
            {
228

  
229
                var credentials = await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
230

  
231
                var account = Accounts.First(act => act.AccountName == credentials.UserName);
232
                //The server may return credentials for a different account
233
                var monitor =  Shell.Monitors[account.AccountName];
234
                account.ApiKey = credentials.Password;
235
                monitor.ApiKey = credentials.Password;
236
                account.IsExpired = false;
237
                Settings.Save();
238
                TaskEx.Delay(10000).ContinueWith(_ =>Shell.MonitorAccount(account.Account));
239
                NotifyOfPropertyChange(() => Accounts);
240
            }
241
            catch (AggregateException exc)
242
            {
243
                string message = String.Format("API Key retrieval failed");
244
                Log.Error(message, exc.InnerException);
245
                _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
246
            }
247
            catch (Exception exc)
248
            {
249
                string message = String.Format("API Key retrieval failed");
250
                Log.Error(message, exc);
251
                _events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
252
            }
253

  
219 254
        }
255

  
220 256
    
221 257
        public void SaveChanges()
222 258
        {
......
298 334
                                        IsActive=wizard.IsAccountActive
299 335
                                    };
300 336
               Settings.Accounts.Add(newAccount);
301
               (Accounts as IProducerConsumerCollection<AccountSettings>).TryAdd(newAccount);
302
               CurrentAccount = newAccount;
337
               var accountVM = new AccountViewModel(newAccount);
338
               (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);
339
               CurrentAccount = accountVM;
303 340
               NotifyOfPropertyChange(() => Accounts);
304 341
               NotifyOfPropertyChange(() => Settings);   
305 342
           }
......
312 349
       {
313 350
            var credentials=await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
314 351
            var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);
352
            var accountVM = new AccountViewModel(account);
315 353
            if (account == null)
316 354
            {
317 355
                account=new AccountSettings{
......
319 357
                    ApiKey=credentials.Password
320 358
                };
321 359
                Settings.Accounts.Add(account);
322
                (Accounts as IProducerConsumerCollection<AccountSettings>).TryAdd(account);
360
                accountVM = new AccountViewModel(account);
361
                (Accounts as IProducerConsumerCollection<AccountViewModel>).TryAdd(accountVM);
323 362
            }
324 363
            else
325 364
            {
326 365
                account.ApiKey=credentials.Password;
327 366
            }
328 367
            //SelectedAccountIndex= Settings.Accounts.IndexOf(account);
329
            CurrentAccount = account;
368
            CurrentAccount = accountVM;
330 369
            NotifyOfPropertyChange(() => Accounts);
331 370
            NotifyOfPropertyChange(()=>Settings);                       
332 371
       }
......
334 373
        public void RemoveAccount()
335 374
        {
336 375
            var accountName = CurrentAccount.AccountName;
337
            Settings.Accounts.Remove(CurrentAccount);
376
            Settings.Accounts.Remove(CurrentAccount.Account);
338 377

  
339 378
            Accounts.TryRemove(CurrentAccount);
340 379
            
......
401 440
            }
402 441
        }*/
403 442

  
404
        private AccountSettings _currentAccount;
443
        private AccountViewModel _currentAccount;
405 444
        private IWindowManager _windowManager;
406 445
        private string _shortcutPath;
407 446

  
408 447

  
409 448
        
410
        public AccountSettings CurrentAccount
449
        public AccountViewModel CurrentAccount
411 450
        {
412 451
            get { return _currentAccount; }
413 452
            set
......
494 533
                    monitor.Start();
495 534
            }
496 535
            else
497
                Shell.MonitorAccount(CurrentAccount);
536
                Shell.MonitorAccount(CurrentAccount.Account);
498 537
            //Finally, notify that the Settings, CurrentAccount have changed
499 538
            NotifyOfPropertyChange(() => CurrentAccount);
500 539
            NotifyOfPropertyChange(() => Settings);
b/trunk/Pithos.Client.WPF/Properties/AssemblyInfo.cs
94 94
// by using the '*' as shown below:
95 95
// [assembly: AssemblyVersion("1.0.*")]
96 96
[assembly: AssemblyVersion("0.7.0.0")]
97
[assembly: AssemblyFileVersionAttribute("0.7.20228.1899")]
97
[assembly: AssemblyFileVersionAttribute("0.7.20229.2112")]
b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
124 124
		//Lazily initialized File Version info. This is done once and lazily to avoid blocking the UI
125 125
		private Lazy<FileVersionInfo> _fileVersion;
126 126

  
127
	    private PollAgent _pollAgent;
128

  
127 129
		///<summary>
128 130
		/// The Shell depends on MEF to provide implementations for windowManager, events, the status checker service and the settings
129 131
		///</summary>
......
131 133
		/// The PithosSettings class encapsulates the app's settings to abstract their storage mechanism (App settings, a database or registry)
132 134
		///</remarks>
133 135
		[ImportingConstructor]		
134
		public ShellViewModel(IWindowManager windowManager, IEventAggregator events, IStatusChecker statusChecker, PithosSettings settings)
136
		public ShellViewModel(IWindowManager windowManager, IEventAggregator events, IStatusChecker statusChecker, PithosSettings settings,PollAgent pollAgent)
135 137
		{
136 138
			try
137 139
			{
......
144 146
				_events = events;
145 147
				_events.Subscribe(this);
146 148

  
149
			    _pollAgent = pollAgent;
147 150
				Settings = settings;
148 151

  
149 152
				Proxy.SetFromSettings(settings);
......
471 474

  
472 475
		public void SynchNow()
473 476
		{
474
			var agent = IoC.Get<PollAgent>();
475
			agent.SynchNow();
477
			_pollAgent.SynchNow();
476 478
		}
477 479

  
478 480
		public ObjectInfo RefreshObjectInfo(ObjectInfo currentInfo)
......
637 639
		}
638 640

  
639 641

  
640
		public async Task TryAuthorize(string userName, int retries)
641
		{
642
			_events.Publish(new Notification { Title = "Authorization failed", Message = "Your API Key has probably expired. You will be directed to a page where you can renew it", Level = TraceLevel.Error });
643

  
644
			try
645
			{
646

  
647
				var credentials = await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
648

  
649
				var account = Settings.Accounts.First(act => act.AccountName == credentials.UserName);
650
                //The server may return credentials for a different account
651
			    var monitor = _monitors[account.AccountName];
652
				account.ApiKey = credentials.Password;
653
                monitor.ApiKey = credentials.Password;
654
			    account.IsExpired = false;
655
				Settings.Save();
656
				TaskEx.Delay(10000).ContinueWith(_=>
657
                            StartMonitor(monitor, retries + 1));
658
				NotifyOfPropertyChange(()=>Accounts);
659
			}
660
			catch (AggregateException exc)
661
			{
662
				string message = String.Format("API Key retrieval for {0} failed", userName);
663
				Log.Error(message, exc.InnerException);
664
				_events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
665
			}
666
			catch (Exception exc)
667
			{
668
				string message = String.Format("API Key retrieval for {0} failed", userName);
669
				Log.Error(message, exc);
670
				_events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
671
			}
672

  
673
		}
674 642

  
675 643
		private static bool IsUnauthorized(WebException exc)
676 644
		{
b/trunk/Pithos.Interfaces/ObjectInfo.cs
53 53
namespace Pithos.Interfaces
54 54
{
55 55
    [DebuggerDisplay("Name {Name}")]
56
    public class ObjectInfo:DynamicObject 
56
    public class ObjectInfo//:DynamicObject 
57 57
    {
58 58
        private readonly List<string> _knownContainers= new List<string>{"trash"};
59 59
        public string Name { get; set; }
......
234 234
            Hash = String.Empty,
235 235
            Bytes = 0,
236 236
            Content_Type = String.Empty,
237
            Last_Modified = DateTime.MinValue
237
            Last_Modified = DateTime.MinValue,
238
            Exists=false
238 239
        };
239 240

  
240
        
241
        private bool _exists=true;
242

  
243
        public bool Exists
244
        {
245
            get {
246
                return _exists;
247
            }
248
            set {
249
                _exists = value;
250
            }
251
        }
252

  
241 253

  
242 254
        public string RelativeUrlToFilePath(string currentAccount)
243 255
        {
......
268 280
            return finalPath;
269 281
        }
270 282

  
283
/*
271 284
        public override bool TrySetMember(SetMemberBinder binder, object value)
272 285
        {
273 286
            if (binder.Name.StartsWith("x_object_meta"))
......
276 289
            }
277 290
            return false;
278 291
        }
292
*/
279 293

  
280 294
        public string GetPermissionString()
281 295
        {
b/trunk/Pithos.Setup.x64/Pithos.Setup.x64.vdproj
1310 1310
        {
1311 1311
        "Name" = "8:Microsoft Visual Studio"
1312 1312
        "ProductName" = "8:Pithos"
1313
        "ProductCode" = "8:{E88F0F45-5BE6-4616-A86B-D595712A5663}"
1314
        "PackageCode" = "8:{8314D97A-C981-4184-8444-4DB962DC3240}"
1313
        "ProductCode" = "8:{013ABFEC-E6FB-4C5E-930F-736A4730268A}"
1314
        "PackageCode" = "8:{C7D65245-240C-42FA-9E46-2AAFB3351131}"
1315 1315
        "UpgradeCode" = "8:{205365D1-28AA-4322-A46C-FCB37502C6EF}"
1316 1316
        "AspNetVersion" = "8:4.0.30319.0"
1317 1317
        "RestartWWWService" = "11:FALSE"
1318 1318
        "RemovePreviousVersions" = "11:TRUE"
1319 1319
        "DetectNewerInstalledVersion" = "11:TRUE"
1320 1320
        "InstallAllUsers" = "11:FALSE"
1321
        "ProductVersion" = "8:0.7.20228"
1321
        "ProductVersion" = "8:0.7.20229"
1322 1322
        "Manufacturer" = "8:GRNET"
1323 1323
        "ARPHELPTELEPHONE" = "8:"
1324 1324
        "ARPHELPLINK" = "8:http://code.grnet.gr/projects/pithos-ms-client"
b/trunk/Pithos.Setup.x86/Pithos.Setup.x86.vdproj
1310 1310
        {
1311 1311
        "Name" = "8:Microsoft Visual Studio"
1312 1312
        "ProductName" = "8:Pithos"
1313
        "ProductCode" = "8:{F70830AB-AE3C-4721-9FBD-2EF0CD415B7D}"
1314
        "PackageCode" = "8:{78D43546-C115-43DE-AAE2-6C262F691990}"
1313
        "ProductCode" = "8:{CDF5C181-8F2F-4135-9861-89F031E4B435}"
1314
        "PackageCode" = "8:{CD80CD47-92C9-4445-A777-4110130323B8}"
1315 1315
        "UpgradeCode" = "8:{205365D1-28AA-4322-A46C-FCB37502C6EF}"
1316 1316
        "AspNetVersion" = "8:4.0.30319.0"
1317 1317
        "RestartWWWService" = "11:FALSE"
1318 1318
        "RemovePreviousVersions" = "11:TRUE"
1319 1319
        "DetectNewerInstalledVersion" = "11:TRUE"
1320 1320
        "InstallAllUsers" = "11:FALSE"
1321
        "ProductVersion" = "8:0.7.20228"
1321
        "ProductVersion" = "8:0.7.20229"
1322 1322
        "Manufacturer" = "8:GRNET"
1323 1323
        "ARPHELPTELEPHONE" = "8:"
1324 1324
        "ARPHELPLINK" = "8:http://code.grnet.gr/projects/pithos-ms-client"

Also available in: Unified diff